doing 1.0.91 → 2.0.3.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/AUTHORS +19 -0
 - data/CHANGELOG.md +590 -0
 - data/COMMANDS.md +1181 -0
 - data/Gemfile +2 -0
 - data/Gemfile.lock +110 -0
 - data/LICENSE +23 -0
 - data/README.md +15 -699
 - data/Rakefile +79 -0
 - data/_config.yml +1 -0
 - data/bin/doing +1012 -486
 - data/doing.fish +278 -0
 - data/doing.gemspec +34 -0
 - data/doing.rdoc +1759 -0
 - data/example_plugin.rb +209 -0
 - data/generate_completions.sh +4 -0
 - data/img/doing-colors.jpg +0 -0
 - data/img/doing-printf-wrap-800.jpg +0 -0
 - data/img/doing-show-note-formatting-800.jpg +0 -0
 - data/lib/completion/_doing.zsh +151 -0
 - data/lib/completion/doing.bash +416 -0
 - data/lib/completion/doing.fish +278 -0
 - data/lib/doing/array.rb +8 -0
 - data/lib/doing/cli_status.rb +66 -0
 - data/lib/doing/colors.rb +136 -0
 - data/lib/doing/configuration.rb +310 -0
 - data/lib/doing/errors.rb +102 -0
 - data/lib/doing/hash.rb +31 -0
 - data/lib/doing/hooks.rb +59 -0
 - data/lib/doing/item.rb +155 -0
 - data/lib/doing/log_adapter.rb +342 -0
 - data/lib/doing/markdown_document_listener.rb +174 -0
 - data/lib/doing/note.rb +59 -0
 - data/lib/doing/pager.rb +95 -0
 - data/lib/doing/plugin_manager.rb +208 -0
 - data/lib/doing/plugins/export/csv_export.rb +48 -0
 - data/lib/doing/plugins/export/html_export.rb +83 -0
 - data/lib/doing/plugins/export/json_export.rb +140 -0
 - data/lib/doing/plugins/export/markdown_export.rb +85 -0
 - data/lib/doing/plugins/export/taskpaper_export.rb +34 -0
 - data/lib/doing/plugins/export/template_export.rb +141 -0
 - data/lib/doing/plugins/import/cal_to_json.scpt +0 -0
 - data/lib/doing/plugins/import/calendar_import.rb +76 -0
 - data/lib/doing/plugins/import/doing_import.rb +144 -0
 - data/lib/doing/plugins/import/timing_import.rb +78 -0
 - data/lib/doing/string.rb +346 -0
 - data/lib/doing/symbol.rb +16 -0
 - data/lib/doing/time.rb +18 -0
 - data/lib/doing/util.rb +186 -0
 - data/lib/doing/version.rb +1 -1
 - data/lib/doing/wwid.rb +1831 -2358
 - data/lib/doing/wwidfile.rb +117 -0
 - data/lib/doing.rb +44 -4
 - data/lib/examples/commands/wiki.rb +80 -0
 - data/lib/examples/plugins/hooks.rb +22 -0
 - data/lib/examples/plugins/say_export.rb +202 -0
 - data/lib/examples/plugins/templates/wiki.css +169 -0
 - data/lib/examples/plugins/templates/wiki.haml +27 -0
 - data/lib/examples/plugins/templates/wiki_index.haml +18 -0
 - data/lib/examples/plugins/wiki_export.rb +87 -0
 - data/lib/templates/doing-markdown.erb +5 -0
 - data/man/doing.1 +964 -0
 - data/man/doing.1.html +711 -0
 - data/man/doing.1.ronn +600 -0
 - data/package-lock.json +3 -0
 - data/rdoc_to_mmd.rb +42 -0
 - data/rdocfixer.rb +13 -0
 - data/scripts/generate_bash_completions.rb +210 -0
 - data/scripts/generate_fish_completions.rb +201 -0
 - data/scripts/generate_zsh_completions.rb +164 -0
 - metadata +82 -6
 - data/lib/doing/helpers.rb +0 -191
 
    
        data/lib/doing/string.rb
    ADDED
    
    | 
         @@ -0,0 +1,346 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Doing
         
     | 
| 
      
 4 
     | 
    
         
            +
              ##
         
     | 
| 
      
 5 
     | 
    
         
            +
              ## @brief      String helpers
         
     | 
| 
      
 6 
     | 
    
         
            +
              ##
         
     | 
| 
      
 7 
     | 
    
         
            +
              class ::String
         
     | 
| 
      
 8 
     | 
    
         
            +
                include Doing::Color
         
     | 
| 
      
 9 
     | 
    
         
            +
                def to_rx(distance)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  gsub(/(.)/, "\\1.{0,#{distance}}")
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def truthy?
         
     | 
| 
      
 14 
     | 
    
         
            +
                  if self =~ /^(0|f(alse)?|n(o)?)$/i
         
     | 
| 
      
 15 
     | 
    
         
            +
                    false
         
     | 
| 
      
 16 
     | 
    
         
            +
                  else
         
     | 
| 
      
 17 
     | 
    
         
            +
                    true
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def highlight_tags!(color = 'yellow')
         
     | 
| 
      
 22 
     | 
    
         
            +
                  replace highlight_tags(color)
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def highlight_tags(color = 'yellow')
         
     | 
| 
      
 26 
     | 
    
         
            +
                  escapes = scan(/(\e\[[\d;]+m)[^\e]+@/)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  tag_color = Doing::Color.send(color)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  last_color = if !escapes.empty?
         
     | 
| 
      
 29 
     | 
    
         
            +
                                 escapes[-1][0]
         
     | 
| 
      
 30 
     | 
    
         
            +
                               else
         
     | 
| 
      
 31 
     | 
    
         
            +
                                 Doing::Color.default
         
     | 
| 
      
 32 
     | 
    
         
            +
                               end
         
     | 
| 
      
 33 
     | 
    
         
            +
                  gsub(/(\s|m)(@[^ ("']+)/, "\\1#{tag_color}\\2#{last_color}")
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                ##
         
     | 
| 
      
 37 
     | 
    
         
            +
                ## @brief      Test if line should be ignored
         
     | 
| 
      
 38 
     | 
    
         
            +
                ##
         
     | 
| 
      
 39 
     | 
    
         
            +
                ## @return     [Boolean] line is empty or comment
         
     | 
| 
      
 40 
     | 
    
         
            +
                ##
         
     | 
| 
      
 41 
     | 
    
         
            +
                def ignore?
         
     | 
| 
      
 42 
     | 
    
         
            +
                  line = self
         
     | 
| 
      
 43 
     | 
    
         
            +
                  line =~ /^#/ || line =~ /^\s*$/
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                ##
         
     | 
| 
      
 47 
     | 
    
         
            +
                ## @brief      Truncate to nearest word
         
     | 
| 
      
 48 
     | 
    
         
            +
                ##
         
     | 
| 
      
 49 
     | 
    
         
            +
                ## @param      len   The length
         
     | 
| 
      
 50 
     | 
    
         
            +
                ##
         
     | 
| 
      
 51 
     | 
    
         
            +
                def truncate(len, ellipsis: '...')
         
     | 
| 
      
 52 
     | 
    
         
            +
                  return self if length <= len
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  total = 0
         
     | 
| 
      
 55 
     | 
    
         
            +
                  res = []
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  split(/ /).each do |word|
         
     | 
| 
      
 58 
     | 
    
         
            +
                    break if total + 1 + word.length > len
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                    total += 1 + word.length
         
     | 
| 
      
 61 
     | 
    
         
            +
                    res.push(word)
         
     | 
| 
      
 62 
     | 
    
         
            +
                  end
         
     | 
| 
      
 63 
     | 
    
         
            +
                  res.join(' ') + ellipsis
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                def truncate!(len, ellipsis: '...')
         
     | 
| 
      
 67 
     | 
    
         
            +
                  replace truncate(len, ellipsis: ellipsis)
         
     | 
| 
      
 68 
     | 
    
         
            +
                end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                ##
         
     | 
| 
      
 71 
     | 
    
         
            +
                ## @brief      Truncate string in the middle
         
     | 
| 
      
 72 
     | 
    
         
            +
                ##
         
     | 
| 
      
 73 
     | 
    
         
            +
                ## @param      len       The length
         
     | 
| 
      
 74 
     | 
    
         
            +
                ## @param      ellipsis  The ellipsis
         
     | 
| 
      
 75 
     | 
    
         
            +
                ##
         
     | 
| 
      
 76 
     | 
    
         
            +
                def truncmiddle(len, ellipsis: '...')
         
     | 
| 
      
 77 
     | 
    
         
            +
                  return self if length <= len
         
     | 
| 
      
 78 
     | 
    
         
            +
                  len -= (ellipsis.length / 2).to_i
         
     | 
| 
      
 79 
     | 
    
         
            +
                  total = length
         
     | 
| 
      
 80 
     | 
    
         
            +
                  half = total / 2
         
     | 
| 
      
 81 
     | 
    
         
            +
                  cut = (total - len) / 2
         
     | 
| 
      
 82 
     | 
    
         
            +
                  sub(/(.{#{half - cut}}).*?(.{#{half - cut}})$/, "\\1#{ellipsis}\\2")
         
     | 
| 
      
 83 
     | 
    
         
            +
                end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                def truncmiddle!(len, ellipsis: '...')
         
     | 
| 
      
 86 
     | 
    
         
            +
                  replace truncmiddle(len, ellipsis: ellipsis)
         
     | 
| 
      
 87 
     | 
    
         
            +
                end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                ##
         
     | 
| 
      
 90 
     | 
    
         
            +
                ## @brief      Remove color escape codes
         
     | 
| 
      
 91 
     | 
    
         
            +
                ##
         
     | 
| 
      
 92 
     | 
    
         
            +
                ## @return     clean string
         
     | 
| 
      
 93 
     | 
    
         
            +
                ##
         
     | 
| 
      
 94 
     | 
    
         
            +
                def uncolor
         
     | 
| 
      
 95 
     | 
    
         
            +
                  gsub(/\e\[[\d;]+m/,'')
         
     | 
| 
      
 96 
     | 
    
         
            +
                end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                def uncolor!
         
     | 
| 
      
 99 
     | 
    
         
            +
                  replace uncolor
         
     | 
| 
      
 100 
     | 
    
         
            +
                end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                ##
         
     | 
| 
      
 103 
     | 
    
         
            +
                ## @brief      Wrap string at word breaks, respecting tags
         
     | 
| 
      
 104 
     | 
    
         
            +
                ##
         
     | 
| 
      
 105 
     | 
    
         
            +
                ## @param      len     [Integer] The length
         
     | 
| 
      
 106 
     | 
    
         
            +
                ## @param      offset  [Integer] (Optional) The width to pad each subsequent line
         
     | 
| 
      
 107 
     | 
    
         
            +
                ## @param      prefix  [String] (Optional) A prefix to add to each line
         
     | 
| 
      
 108 
     | 
    
         
            +
                ##
         
     | 
| 
      
 109 
     | 
    
         
            +
                def wrap(len, pad: 0, indent: '  ', offset: 0, prefix: '', after: '', reset: '')
         
     | 
| 
      
 110 
     | 
    
         
            +
                  note_rx = /(?i-m)(%(?:[io]d|(?:\^[\s\S])?(?:(?:[ _t]|[^a-z0-9])?\d+)?(?:[\s\S][ _t]?)?)?note)/
         
     | 
| 
      
 111 
     | 
    
         
            +
                  str = gsub(/@\w+\(.*?\)/) { |tag| tag.gsub(/\s/, '%%%%') }
         
     | 
| 
      
 112 
     | 
    
         
            +
                  words = str.split(/ /).map { |word| word.gsub(/%%%%/, ' ') }
         
     | 
| 
      
 113 
     | 
    
         
            +
                  out = []
         
     | 
| 
      
 114 
     | 
    
         
            +
                  line = []
         
     | 
| 
      
 115 
     | 
    
         
            +
                  words.each do |word|
         
     | 
| 
      
 116 
     | 
    
         
            +
                    if line.join(' ').length + word.length + 1 > len
         
     | 
| 
      
 117 
     | 
    
         
            +
                      out.push(line.join(' '))
         
     | 
| 
      
 118 
     | 
    
         
            +
                      line.clear
         
     | 
| 
      
 119 
     | 
    
         
            +
                    end
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
                    line << word
         
     | 
| 
      
 122 
     | 
    
         
            +
                  end
         
     | 
| 
      
 123 
     | 
    
         
            +
                  out.push(line.join(' '))
         
     | 
| 
      
 124 
     | 
    
         
            +
                  note = ''
         
     | 
| 
      
 125 
     | 
    
         
            +
                  after.sub!(note_rx) do
         
     | 
| 
      
 126 
     | 
    
         
            +
                    note = Regexp.last_match(0)
         
     | 
| 
      
 127 
     | 
    
         
            +
                    ''
         
     | 
| 
      
 128 
     | 
    
         
            +
                  end
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                  out[0] = format("%-#{pad}s%s", out[0], after)
         
     | 
| 
      
 131 
     | 
    
         
            +
                  left_pad = ' ' * (offset)
         
     | 
| 
      
 132 
     | 
    
         
            +
                  left_pad += indent
         
     | 
| 
      
 133 
     | 
    
         
            +
                  out.map { |l| "#{left_pad}#{prefix}#{l}" }.join("\n").strip + " #{note}".chomp
         
     | 
| 
      
 134 
     | 
    
         
            +
                end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                ##
         
     | 
| 
      
 137 
     | 
    
         
            +
                ## @brief      Capitalize on the first character on string
         
     | 
| 
      
 138 
     | 
    
         
            +
                ##
         
     | 
| 
      
 139 
     | 
    
         
            +
                ## @return     Capitalized string
         
     | 
| 
      
 140 
     | 
    
         
            +
                ##
         
     | 
| 
      
 141 
     | 
    
         
            +
                def cap_first
         
     | 
| 
      
 142 
     | 
    
         
            +
                  sub(/^\w/) do |m|
         
     | 
| 
      
 143 
     | 
    
         
            +
                    m.upcase
         
     | 
| 
      
 144 
     | 
    
         
            +
                  end
         
     | 
| 
      
 145 
     | 
    
         
            +
                end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                ##
         
     | 
| 
      
 148 
     | 
    
         
            +
                ## @brief      Convert a sort order string to a qualified type
         
     | 
| 
      
 149 
     | 
    
         
            +
                ##
         
     | 
| 
      
 150 
     | 
    
         
            +
                ## @return     (String) 'asc' or 'desc'
         
     | 
| 
      
 151 
     | 
    
         
            +
                ##
         
     | 
| 
      
 152 
     | 
    
         
            +
                def normalize_order!
         
     | 
| 
      
 153 
     | 
    
         
            +
                  replace normalize_order
         
     | 
| 
      
 154 
     | 
    
         
            +
                end
         
     | 
| 
      
 155 
     | 
    
         
            +
             
     | 
| 
      
 156 
     | 
    
         
            +
                def normalize_order(default = 'asc')
         
     | 
| 
      
 157 
     | 
    
         
            +
                  case self
         
     | 
| 
      
 158 
     | 
    
         
            +
                  when /^a/i
         
     | 
| 
      
 159 
     | 
    
         
            +
                    'asc'
         
     | 
| 
      
 160 
     | 
    
         
            +
                  when /^d/i
         
     | 
| 
      
 161 
     | 
    
         
            +
                    'desc'
         
     | 
| 
      
 162 
     | 
    
         
            +
                  else
         
     | 
| 
      
 163 
     | 
    
         
            +
                    default
         
     | 
| 
      
 164 
     | 
    
         
            +
                  end
         
     | 
| 
      
 165 
     | 
    
         
            +
                end
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                ##
         
     | 
| 
      
 168 
     | 
    
         
            +
                ## @brief      Convert a boolean string to a symbol
         
     | 
| 
      
 169 
     | 
    
         
            +
                ##
         
     | 
| 
      
 170 
     | 
    
         
            +
                ## @return     Symbol :and, :or, or :not
         
     | 
| 
      
 171 
     | 
    
         
            +
                ##
         
     | 
| 
      
 172 
     | 
    
         
            +
                def normalize_bool!
         
     | 
| 
      
 173 
     | 
    
         
            +
                  replace normalize_bool
         
     | 
| 
      
 174 
     | 
    
         
            +
                end
         
     | 
| 
      
 175 
     | 
    
         
            +
             
     | 
| 
      
 176 
     | 
    
         
            +
                def normalize_bool(default = :and)
         
     | 
| 
      
 177 
     | 
    
         
            +
                  case self
         
     | 
| 
      
 178 
     | 
    
         
            +
                  when /(and|all)/i
         
     | 
| 
      
 179 
     | 
    
         
            +
                    :and
         
     | 
| 
      
 180 
     | 
    
         
            +
                  when /(any|or)/i
         
     | 
| 
      
 181 
     | 
    
         
            +
                    :or
         
     | 
| 
      
 182 
     | 
    
         
            +
                  when /(not|none)/i
         
     | 
| 
      
 183 
     | 
    
         
            +
                    :not
         
     | 
| 
      
 184 
     | 
    
         
            +
                  else
         
     | 
| 
      
 185 
     | 
    
         
            +
                    default.is_a?(Symbol) ? default : default.normalize_bool
         
     | 
| 
      
 186 
     | 
    
         
            +
                  end
         
     | 
| 
      
 187 
     | 
    
         
            +
                end
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
                def normalize_trigger!
         
     | 
| 
      
 190 
     | 
    
         
            +
                  replace normalize_trigger
         
     | 
| 
      
 191 
     | 
    
         
            +
                end
         
     | 
| 
      
 192 
     | 
    
         
            +
             
     | 
| 
      
 193 
     | 
    
         
            +
                def normalize_trigger
         
     | 
| 
      
 194 
     | 
    
         
            +
                  gsub(/\((?!\?:)/, '(?:').downcase
         
     | 
| 
      
 195 
     | 
    
         
            +
                end
         
     | 
| 
      
 196 
     | 
    
         
            +
             
     | 
| 
      
 197 
     | 
    
         
            +
                def to_tags
         
     | 
| 
      
 198 
     | 
    
         
            +
                  gsub(/ *, */, ' ').gsub(/ +/, ' ').split(/ /).sort.uniq.map { |t| t.strip.sub(/^@/, '') }
         
     | 
| 
      
 199 
     | 
    
         
            +
                end
         
     | 
| 
      
 200 
     | 
    
         
            +
             
     | 
| 
      
 201 
     | 
    
         
            +
                def add_tags!(tags, remove: false)
         
     | 
| 
      
 202 
     | 
    
         
            +
                  replace add_tags(tags, remove: remove)
         
     | 
| 
      
 203 
     | 
    
         
            +
                end
         
     | 
| 
      
 204 
     | 
    
         
            +
             
     | 
| 
      
 205 
     | 
    
         
            +
                def add_tags(tags, remove: false)
         
     | 
| 
      
 206 
     | 
    
         
            +
                  title = self.dup
         
     | 
| 
      
 207 
     | 
    
         
            +
                  tags = tags.to_tags if tags.is_a?(String)
         
     | 
| 
      
 208 
     | 
    
         
            +
                  tags.each { |tag| title.tag!(tag, remove: remove) }
         
     | 
| 
      
 209 
     | 
    
         
            +
                  title
         
     | 
| 
      
 210 
     | 
    
         
            +
                end
         
     | 
| 
      
 211 
     | 
    
         
            +
             
     | 
| 
      
 212 
     | 
    
         
            +
                def tag!(tag, value: nil, remove: false, rename_to: nil, regex: false)
         
     | 
| 
      
 213 
     | 
    
         
            +
                  replace tag(tag, value: value, remove: remove, rename_to: rename_to, regex: regex)
         
     | 
| 
      
 214 
     | 
    
         
            +
                end
         
     | 
| 
      
 215 
     | 
    
         
            +
             
     | 
| 
      
 216 
     | 
    
         
            +
                def tag(tag, value: nil, remove: false, rename_to: nil, regex: false)
         
     | 
| 
      
 217 
     | 
    
         
            +
                  title = dup
         
     | 
| 
      
 218 
     | 
    
         
            +
                  title.chomp!
         
     | 
| 
      
 219 
     | 
    
         
            +
                  tag = tag.sub(/^@?/, '')
         
     | 
| 
      
 220 
     | 
    
         
            +
                  case_sensitive = tag !~ /[A-Z]/
         
     | 
| 
      
 221 
     | 
    
         
            +
             
     | 
| 
      
 222 
     | 
    
         
            +
                  rx_tag = if regex
         
     | 
| 
      
 223 
     | 
    
         
            +
                             tag.gsub(/\./, '\S')
         
     | 
| 
      
 224 
     | 
    
         
            +
                           else
         
     | 
| 
      
 225 
     | 
    
         
            +
                             tag.gsub(/\?/, '.').gsub(/\*/, '\S*?')
         
     | 
| 
      
 226 
     | 
    
         
            +
                           end
         
     | 
| 
      
 227 
     | 
    
         
            +
             
     | 
| 
      
 228 
     | 
    
         
            +
                  if remove || rename_to
         
     | 
| 
      
 229 
     | 
    
         
            +
                    return title unless title =~ /#{rx_tag}(?=[ (]|$)/
         
     | 
| 
      
 230 
     | 
    
         
            +
             
     | 
| 
      
 231 
     | 
    
         
            +
                    rx = Regexp.new("(^| )@#{rx_tag}(\\([^)]*\\))?(?= |$)", case_sensitive)
         
     | 
| 
      
 232 
     | 
    
         
            +
                    if title =~ rx
         
     | 
| 
      
 233 
     | 
    
         
            +
                      title.gsub!(rx) do
         
     | 
| 
      
 234 
     | 
    
         
            +
                        m = Regexp.last_match
         
     | 
| 
      
 235 
     | 
    
         
            +
                        rename_to ? "#{m[1]}@#{rename_to}#{m[2]}" : m[1]
         
     | 
| 
      
 236 
     | 
    
         
            +
                      end
         
     | 
| 
      
 237 
     | 
    
         
            +
             
     | 
| 
      
 238 
     | 
    
         
            +
                      title.dedup_tags!
         
     | 
| 
      
 239 
     | 
    
         
            +
                      title.chomp!
         
     | 
| 
      
 240 
     | 
    
         
            +
             
     | 
| 
      
 241 
     | 
    
         
            +
                      if rename_to
         
     | 
| 
      
 242 
     | 
    
         
            +
                        f = "@#{tag}".cyan
         
     | 
| 
      
 243 
     | 
    
         
            +
                        t = "@#{rename_to}".cyan
         
     | 
| 
      
 244 
     | 
    
         
            +
                        Doing.logger.debug('Tag:', %(renamed #{f} to #{t} in "#{title}"))
         
     | 
| 
      
 245 
     | 
    
         
            +
                      else
         
     | 
| 
      
 246 
     | 
    
         
            +
                        f = "@#{tag}".cyan
         
     | 
| 
      
 247 
     | 
    
         
            +
                        Doing.logger.debug('Tag:', %(removed #{f} from "#{title}"))
         
     | 
| 
      
 248 
     | 
    
         
            +
                      end
         
     | 
| 
      
 249 
     | 
    
         
            +
                    else
         
     | 
| 
      
 250 
     | 
    
         
            +
                      Doing.logger.debug('Skipped:', "not tagged #{"@#{tag}".cyan}")
         
     | 
| 
      
 251 
     | 
    
         
            +
                    end
         
     | 
| 
      
 252 
     | 
    
         
            +
                  elsif title =~ /@#{tag}(?=[ (]|$)/
         
     | 
| 
      
 253 
     | 
    
         
            +
                    Doing.logger.debug('Skipped:', "already tagged #{"@#{tag}".cyan}")
         
     | 
| 
      
 254 
     | 
    
         
            +
                    return title
         
     | 
| 
      
 255 
     | 
    
         
            +
                  else
         
     | 
| 
      
 256 
     | 
    
         
            +
                    add = tag
         
     | 
| 
      
 257 
     | 
    
         
            +
                    add += "(#{value})" unless value.nil?
         
     | 
| 
      
 258 
     | 
    
         
            +
                    title += " @#{add}"
         
     | 
| 
      
 259 
     | 
    
         
            +
             
     | 
| 
      
 260 
     | 
    
         
            +
                    title.dedup_tags!
         
     | 
| 
      
 261 
     | 
    
         
            +
                    title.chomp!
         
     | 
| 
      
 262 
     | 
    
         
            +
                    # Doing.logger.debug('Added tag:', %(#{('@' + tag).cyan} to "#{title}"))
         
     | 
| 
      
 263 
     | 
    
         
            +
                  end
         
     | 
| 
      
 264 
     | 
    
         
            +
             
     | 
| 
      
 265 
     | 
    
         
            +
                  title
         
     | 
| 
      
 266 
     | 
    
         
            +
                end
         
     | 
| 
      
 267 
     | 
    
         
            +
             
     | 
| 
      
 268 
     | 
    
         
            +
                ##
         
     | 
| 
      
 269 
     | 
    
         
            +
                ## @brief      Remove duplicate tags, leaving only first occurrence
         
     | 
| 
      
 270 
     | 
    
         
            +
                ##
         
     | 
| 
      
 271 
     | 
    
         
            +
                ## @return     Deduplicated string
         
     | 
| 
      
 272 
     | 
    
         
            +
                ##
         
     | 
| 
      
 273 
     | 
    
         
            +
                def dedup_tags!
         
     | 
| 
      
 274 
     | 
    
         
            +
                  replace dedup_tags
         
     | 
| 
      
 275 
     | 
    
         
            +
                end
         
     | 
| 
      
 276 
     | 
    
         
            +
             
     | 
| 
      
 277 
     | 
    
         
            +
                def dedup_tags
         
     | 
| 
      
 278 
     | 
    
         
            +
                  title = dup
         
     | 
| 
      
 279 
     | 
    
         
            +
                  tags = title.scan(/(?<=^| )(@(\S+?)(\([^)]+\))?)(?= |$)/).uniq
         
     | 
| 
      
 280 
     | 
    
         
            +
                  tags.each do |tag|
         
     | 
| 
      
 281 
     | 
    
         
            +
                    found = false
         
     | 
| 
      
 282 
     | 
    
         
            +
                    title.gsub!(/( |^)#{tag[1]}(\([^)]+\))?(?= |$)/) do |m|
         
     | 
| 
      
 283 
     | 
    
         
            +
                      if found
         
     | 
| 
      
 284 
     | 
    
         
            +
                        ''
         
     | 
| 
      
 285 
     | 
    
         
            +
                      else
         
     | 
| 
      
 286 
     | 
    
         
            +
                        found = true
         
     | 
| 
      
 287 
     | 
    
         
            +
                        m
         
     | 
| 
      
 288 
     | 
    
         
            +
                      end
         
     | 
| 
      
 289 
     | 
    
         
            +
                    end
         
     | 
| 
      
 290 
     | 
    
         
            +
                  end
         
     | 
| 
      
 291 
     | 
    
         
            +
                  title
         
     | 
| 
      
 292 
     | 
    
         
            +
                end
         
     | 
| 
      
 293 
     | 
    
         
            +
             
     | 
| 
      
 294 
     | 
    
         
            +
                ##
         
     | 
| 
      
 295 
     | 
    
         
            +
                ## @brief      Turn raw urls into HTML links
         
     | 
| 
      
 296 
     | 
    
         
            +
                ##
         
     | 
| 
      
 297 
     | 
    
         
            +
                ## @param      opt   (Hash) Additional Options
         
     | 
| 
      
 298 
     | 
    
         
            +
                ##
         
     | 
| 
      
 299 
     | 
    
         
            +
                def link_urls!(opt = {})
         
     | 
| 
      
 300 
     | 
    
         
            +
                  replace link_urls(opt)
         
     | 
| 
      
 301 
     | 
    
         
            +
                end
         
     | 
| 
      
 302 
     | 
    
         
            +
             
     | 
| 
      
 303 
     | 
    
         
            +
                def link_urls(opt = {})
         
     | 
| 
      
 304 
     | 
    
         
            +
                  opt[:format] ||= :html
         
     | 
| 
      
 305 
     | 
    
         
            +
                  str = self.dup
         
     | 
| 
      
 306 
     | 
    
         
            +
             
     | 
| 
      
 307 
     | 
    
         
            +
                  if :format == :markdown
         
     | 
| 
      
 308 
     | 
    
         
            +
                    # Remove <self-linked> formatting
         
     | 
| 
      
 309 
     | 
    
         
            +
                    str.gsub!(/<(.*?)>/) do |match|
         
     | 
| 
      
 310 
     | 
    
         
            +
                      m = Regexp.last_match
         
     | 
| 
      
 311 
     | 
    
         
            +
                      if m[1] =~ /^https?:/
         
     | 
| 
      
 312 
     | 
    
         
            +
                        m[1]
         
     | 
| 
      
 313 
     | 
    
         
            +
                      else
         
     | 
| 
      
 314 
     | 
    
         
            +
                        match
         
     | 
| 
      
 315 
     | 
    
         
            +
                      end
         
     | 
| 
      
 316 
     | 
    
         
            +
                    end
         
     | 
| 
      
 317 
     | 
    
         
            +
                  end
         
     | 
| 
      
 318 
     | 
    
         
            +
             
     | 
| 
      
 319 
     | 
    
         
            +
                  # Replace qualified urls
         
     | 
| 
      
 320 
     | 
    
         
            +
                  str.gsub!(%r{(?mi)(?<!["'\[(\\])((http|https)://)([\w\-_]+(\.[\w\-_]+)+)([\w\-.,@?^=%&:/~+#]*[\w\-@^=%&/~+#])?}) do |_match|
         
     | 
| 
      
 321 
     | 
    
         
            +
                    m = Regexp.last_match
         
     | 
| 
      
 322 
     | 
    
         
            +
                    proto = m[1].nil? ? 'http://' : ''
         
     | 
| 
      
 323 
     | 
    
         
            +
                    case opt[:format]
         
     | 
| 
      
 324 
     | 
    
         
            +
                    when :html
         
     | 
| 
      
 325 
     | 
    
         
            +
                      %(<a href="#{proto}#{m[0]}" title="Link to #{m[0].sub(/^https?:\/\//, '')}">[#{m[3]}]</a>)
         
     | 
| 
      
 326 
     | 
    
         
            +
                    when :markdown
         
     | 
| 
      
 327 
     | 
    
         
            +
                      "[#{m[0]}](#{proto}#{m[0]})"
         
     | 
| 
      
 328 
     | 
    
         
            +
                    else
         
     | 
| 
      
 329 
     | 
    
         
            +
                      m[0]
         
     | 
| 
      
 330 
     | 
    
         
            +
                    end
         
     | 
| 
      
 331 
     | 
    
         
            +
                  end
         
     | 
| 
      
 332 
     | 
    
         
            +
             
     | 
| 
      
 333 
     | 
    
         
            +
                  # Clean up unlinked <urls>
         
     | 
| 
      
 334 
     | 
    
         
            +
                  str.gsub!(/<(\w+:.*?)>/) do |match|
         
     | 
| 
      
 335 
     | 
    
         
            +
                    m = Regexp.last_match
         
     | 
| 
      
 336 
     | 
    
         
            +
                    if m[1] =~ /<a href/
         
     | 
| 
      
 337 
     | 
    
         
            +
                      match
         
     | 
| 
      
 338 
     | 
    
         
            +
                    else
         
     | 
| 
      
 339 
     | 
    
         
            +
                      %(<a href="#{m[1]}" title="Link to #{m[1]}">[link]</a>)
         
     | 
| 
      
 340 
     | 
    
         
            +
                    end
         
     | 
| 
      
 341 
     | 
    
         
            +
                  end
         
     | 
| 
      
 342 
     | 
    
         
            +
             
     | 
| 
      
 343 
     | 
    
         
            +
                  str
         
     | 
| 
      
 344 
     | 
    
         
            +
                end
         
     | 
| 
      
 345 
     | 
    
         
            +
              end
         
     | 
| 
      
 346 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/doing/symbol.rb
    ADDED
    
    
    
        data/lib/doing/time.rb
    ADDED
    
    | 
         @@ -0,0 +1,18 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Doing
         
     | 
| 
      
 2 
     | 
    
         
            +
              ##
         
     | 
| 
      
 3 
     | 
    
         
            +
              ## @brief      Date helpers
         
     | 
| 
      
 4 
     | 
    
         
            +
              ##
         
     | 
| 
      
 5 
     | 
    
         
            +
              class ::Time
         
     | 
| 
      
 6 
     | 
    
         
            +
                def relative_date
         
     | 
| 
      
 7 
     | 
    
         
            +
                  if self > Date.today.to_time
         
     | 
| 
      
 8 
     | 
    
         
            +
                    strftime('%_I:%M%P')
         
     | 
| 
      
 9 
     | 
    
         
            +
                  elsif self > (Date.today - 6).to_time
         
     | 
| 
      
 10 
     | 
    
         
            +
                    strftime('%a %_I:%M%P')
         
     | 
| 
      
 11 
     | 
    
         
            +
                  elsif self.year == Date.today.year
         
     | 
| 
      
 12 
     | 
    
         
            +
                    strftime('%m/%d %_I:%M%P')
         
     | 
| 
      
 13 
     | 
    
         
            +
                  else
         
     | 
| 
      
 14 
     | 
    
         
            +
                    strftime('%m/%d/%Y %_I:%M%P')
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/doing/util.rb
    ADDED
    
    | 
         @@ -0,0 +1,186 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Doing
         
     | 
| 
      
 4 
     | 
    
         
            +
              # Utilities
         
     | 
| 
      
 5 
     | 
    
         
            +
              module Util
         
     | 
| 
      
 6 
     | 
    
         
            +
                extend self
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def user_home
         
     | 
| 
      
 9 
     | 
    
         
            +
                  if Dir.respond_to?('home')
         
     | 
| 
      
 10 
     | 
    
         
            +
                    Dir.home
         
     | 
| 
      
 11 
     | 
    
         
            +
                  else
         
     | 
| 
      
 12 
     | 
    
         
            +
                    File.expand_path('~')
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                ##
         
     | 
| 
      
 17 
     | 
    
         
            +
                ## @brief      Test if command line tool is available
         
     | 
| 
      
 18 
     | 
    
         
            +
                ##
         
     | 
| 
      
 19 
     | 
    
         
            +
                ## @param      cli   (String) The name or path of the cli
         
     | 
| 
      
 20 
     | 
    
         
            +
                ##
         
     | 
| 
      
 21 
     | 
    
         
            +
                def exec_available(cli)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  return false if cli.nil?
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  if File.exist?(File.expand_path(cli))
         
     | 
| 
      
 25 
     | 
    
         
            +
                    File.executable?(File.expand_path(cli))
         
     | 
| 
      
 26 
     | 
    
         
            +
                  else
         
     | 
| 
      
 27 
     | 
    
         
            +
                    system "which #{cli}", out: File::NULL, err: File::NULL
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                def merge_default_proc(target, overwrite)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  return unless target.is_a?(Hash) && overwrite.is_a?(Hash) && target.default_proc.nil?
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  target.default_proc = overwrite.default_proc
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                def duplicate_frozen_values(target)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  target.each do |key, val|
         
     | 
| 
      
 39 
     | 
    
         
            +
                    target[key] = val.dup if val.frozen? && duplicable?(val)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                # Non-destructive version of deep_merge_hashes! See that method.
         
     | 
| 
      
 44 
     | 
    
         
            +
                #
         
     | 
| 
      
 45 
     | 
    
         
            +
                # Returns the merged hashes.
         
     | 
| 
      
 46 
     | 
    
         
            +
                def deep_merge_hashes(master_hash, other_hash)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  deep_merge_hashes!(master_hash.dup, other_hash)
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                # Merges a master hash with another hash, recursively.
         
     | 
| 
      
 51 
     | 
    
         
            +
                #
         
     | 
| 
      
 52 
     | 
    
         
            +
                # master_hash - the "parent" hash whose values will be overridden
         
     | 
| 
      
 53 
     | 
    
         
            +
                # other_hash  - the other hash whose values will be persisted after the merge
         
     | 
| 
      
 54 
     | 
    
         
            +
                #
         
     | 
| 
      
 55 
     | 
    
         
            +
                # This code was lovingly stolen from some random gem:
         
     | 
| 
      
 56 
     | 
    
         
            +
                # http://gemjack.com/gems/tartan-0.1.1/classes/Hash.html
         
     | 
| 
      
 57 
     | 
    
         
            +
                #
         
     | 
| 
      
 58 
     | 
    
         
            +
                # Thanks to whoever made it.
         
     | 
| 
      
 59 
     | 
    
         
            +
                def deep_merge_hashes!(target, overwrite)
         
     | 
| 
      
 60 
     | 
    
         
            +
                  merge_values(target, overwrite)
         
     | 
| 
      
 61 
     | 
    
         
            +
                  merge_default_proc(target, overwrite)
         
     | 
| 
      
 62 
     | 
    
         
            +
                  duplicate_frozen_values(target)
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                  target
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                def duplicable?(obj)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  case obj
         
     | 
| 
      
 69 
     | 
    
         
            +
                  when nil, false, true, Symbol, Numeric
         
     | 
| 
      
 70 
     | 
    
         
            +
                    false
         
     | 
| 
      
 71 
     | 
    
         
            +
                  else
         
     | 
| 
      
 72 
     | 
    
         
            +
                    true
         
     | 
| 
      
 73 
     | 
    
         
            +
                  end
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                def mergable?(value)
         
     | 
| 
      
 77 
     | 
    
         
            +
                  value.is_a?(Hash)
         
     | 
| 
      
 78 
     | 
    
         
            +
                end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                def merge_values(target, overwrite)
         
     | 
| 
      
 81 
     | 
    
         
            +
                  target.merge!(overwrite) do |_key, old_val, new_val|
         
     | 
| 
      
 82 
     | 
    
         
            +
                    if new_val.nil?
         
     | 
| 
      
 83 
     | 
    
         
            +
                      old_val
         
     | 
| 
      
 84 
     | 
    
         
            +
                    elsif mergable?(old_val) && mergable?(new_val)
         
     | 
| 
      
 85 
     | 
    
         
            +
                      deep_merge_hashes(old_val, new_val)
         
     | 
| 
      
 86 
     | 
    
         
            +
                    else
         
     | 
| 
      
 87 
     | 
    
         
            +
                      new_val
         
     | 
| 
      
 88 
     | 
    
         
            +
                    end
         
     | 
| 
      
 89 
     | 
    
         
            +
                  end
         
     | 
| 
      
 90 
     | 
    
         
            +
                end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                ##
         
     | 
| 
      
 93 
     | 
    
         
            +
                ## @brief      Write content to a file
         
     | 
| 
      
 94 
     | 
    
         
            +
                ##
         
     | 
| 
      
 95 
     | 
    
         
            +
                ## @param      file     (String) The path to the file to (over)write
         
     | 
| 
      
 96 
     | 
    
         
            +
                ## @param      content  (String) The content to write to the file
         
     | 
| 
      
 97 
     | 
    
         
            +
                ## @param      backup   (Boolean) create a ~ backup
         
     | 
| 
      
 98 
     | 
    
         
            +
                ##
         
     | 
| 
      
 99 
     | 
    
         
            +
                def write_to_file(file, content, backup: true)
         
     | 
| 
      
 100 
     | 
    
         
            +
                  unless file
         
     | 
| 
      
 101 
     | 
    
         
            +
                    puts content
         
     | 
| 
      
 102 
     | 
    
         
            +
                    return
         
     | 
| 
      
 103 
     | 
    
         
            +
                  end
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                  file = File.expand_path(file)
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                  if File.exist?(file) && backup
         
     | 
| 
      
 108 
     | 
    
         
            +
                    # Create a backup copy for the undo command
         
     | 
| 
      
 109 
     | 
    
         
            +
                    FileUtils.cp(file, "#{file}~")
         
     | 
| 
      
 110 
     | 
    
         
            +
                  end
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                  File.open(file, 'w+') do |f|
         
     | 
| 
      
 113 
     | 
    
         
            +
                    f.puts content
         
     | 
| 
      
 114 
     | 
    
         
            +
                  end
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                  Hooks.trigger :post_write, file
         
     | 
| 
      
 117 
     | 
    
         
            +
                end
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
                def safe_load_file(filename)
         
     | 
| 
      
 120 
     | 
    
         
            +
                  SafeYAML.load_file(filename) || {}
         
     | 
| 
      
 121 
     | 
    
         
            +
                end
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                def default_editor
         
     | 
| 
      
 124 
     | 
    
         
            +
                  @default_editor = find_default_editor
         
     | 
| 
      
 125 
     | 
    
         
            +
                end
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
                def editor_with_args
         
     | 
| 
      
 128 
     | 
    
         
            +
                  args_for_editor(default_editor)
         
     | 
| 
      
 129 
     | 
    
         
            +
                end
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
                def args_for_editor(editor)
         
     | 
| 
      
 132 
     | 
    
         
            +
                  return editor if editor =~ /-\S/
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                  args = case editor
         
     | 
| 
      
 135 
     | 
    
         
            +
                         when /^(subl|code|mate)$/
         
     | 
| 
      
 136 
     | 
    
         
            +
                           ['-w']
         
     | 
| 
      
 137 
     | 
    
         
            +
                         when /^(vim|mvim)$/
         
     | 
| 
      
 138 
     | 
    
         
            +
                           ['-f']
         
     | 
| 
      
 139 
     | 
    
         
            +
                         else
         
     | 
| 
      
 140 
     | 
    
         
            +
                           []
         
     | 
| 
      
 141 
     | 
    
         
            +
                         end
         
     | 
| 
      
 142 
     | 
    
         
            +
                  "#{editor} #{args.join(' ')}"
         
     | 
| 
      
 143 
     | 
    
         
            +
                end
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
                def find_default_editor(editor_for = 'default')
         
     | 
| 
      
 146 
     | 
    
         
            +
                  if ENV['DOING_EDITOR_TEST']
         
     | 
| 
      
 147 
     | 
    
         
            +
                    return ENV['EDITOR']
         
     | 
| 
      
 148 
     | 
    
         
            +
                  end
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
                  editor_config = Doing.config.settings['editors']
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                  if editor_config.is_a?(String)
         
     | 
| 
      
 153 
     | 
    
         
            +
                    Doing.logger.warn('Deprecated:', "Please update your configuration, 'editors' should be a mapping. Delete the key and run `doing config --update`.")
         
     | 
| 
      
 154 
     | 
    
         
            +
                    return editor_config
         
     | 
| 
      
 155 
     | 
    
         
            +
                  end
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
                  if editor_config[editor_for]
         
     | 
| 
      
 158 
     | 
    
         
            +
                    editor = editor_config[editor_for]
         
     | 
| 
      
 159 
     | 
    
         
            +
                    Doing.logger.debug('Editor:', "Using #{editor} from config 'editors->#{editor_for}'")
         
     | 
| 
      
 160 
     | 
    
         
            +
                    return editor unless editor.nil? || editor.empty?
         
     | 
| 
      
 161 
     | 
    
         
            +
                  end
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
                  if editor_for != 'editor' && editor_config['default']
         
     | 
| 
      
 164 
     | 
    
         
            +
                    editor = editor_config['default']
         
     | 
| 
      
 165 
     | 
    
         
            +
                    Doing.logger.debug('Editor:', "Using #{editor} from config: 'editors->default'")
         
     | 
| 
      
 166 
     | 
    
         
            +
                    return editor unless editor.nil? || editor.empty?
         
     | 
| 
      
 167 
     | 
    
         
            +
                  end
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
                  editor ||= ENV['DOING_EDITOR'] || ENV['GIT_EDITOR'] || ENV['EDITOR']
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
                  unless editor.nil? || editor.empty?
         
     | 
| 
      
 172 
     | 
    
         
            +
                    Doing.logger.debug('Editor:', "Found editor in environment variables: #{editor}")
         
     | 
| 
      
 173 
     | 
    
         
            +
                    return editor
         
     | 
| 
      
 174 
     | 
    
         
            +
                  end
         
     | 
| 
      
 175 
     | 
    
         
            +
             
     | 
| 
      
 176 
     | 
    
         
            +
                  Doing.logger.debug('ENV:', 'No EDITOR environment variable, testing available editors')
         
     | 
| 
      
 177 
     | 
    
         
            +
                  editors = %w[vim vi code subl mate mvim nano emacs]
         
     | 
| 
      
 178 
     | 
    
         
            +
                  editors.each do |ed|
         
     | 
| 
      
 179 
     | 
    
         
            +
                    return ed if exec_available(ed)
         
     | 
| 
      
 180 
     | 
    
         
            +
                    Doing.logger.debug('ENV:', "#{ed} not available")
         
     | 
| 
      
 181 
     | 
    
         
            +
                  end
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
                  nil
         
     | 
| 
      
 184 
     | 
    
         
            +
                end
         
     | 
| 
      
 185 
     | 
    
         
            +
              end
         
     | 
| 
      
 186 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/doing/version.rb
    CHANGED