howzit 2.1.10 → 2.1.13
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/.rubocop.yml +36 -0
- data/CHANGELOG.md +12 -0
- data/Gemfile +3 -0
- data/README.md +3 -4
- data/Rakefile +31 -0
- data/lib/howzit/buildnote.rb +23 -21
- data/lib/howzit/colors.rb +30 -4
- data/lib/howzit/config.rb +3 -1
- data/lib/howzit/prompt.rb +1 -1
- data/lib/howzit/stringutils.rb +5 -5
- data/lib/howzit/task.rb +4 -3
- data/lib/howzit/topic.rb +182 -160
- data/lib/howzit/util.rb +27 -0
- data/lib/howzit/version.rb +1 -1
- data/lib/howzit.rb +2 -3
- data/spec/topic_spec.rb +11 -4
- data/src/_README.md +145 -0
- metadata +4 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: f0fc931036b21c7bb13c805751a146432d14c40a9a910fd9999aa42fb34658cb
         | 
| 4 | 
            +
              data.tar.gz: 31b927c85e4c7ba6938eff929e7670c1a997d79f21053ce230da3a1a5ca4b246
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 6382fd78151da4a021d605276121fc48f0b1cb7692ee3a4657fd4dee820577f0f5357aa98be565dd120e440619906b1881da2269fe0e53c2321160a34dee26ac
         | 
| 7 | 
            +
              data.tar.gz: d402a1dcf7715f04ed32fc282450c4132bf13cd3a43830eb464c298f79dc86fa4c47f30a6bd8d3698e588468f107b0b4eae6ad90c89195d878ef1f610846ab78
         | 
    
        data/.rubocop.yml
    CHANGED
    
    | @@ -1,15 +1,51 @@ | |
| 1 | 
            +
            require:
         | 
| 2 | 
            +
              - rubocop-rspec
         | 
| 3 | 
            +
              - rubocop-rake
         | 
| 4 | 
            +
             | 
| 1 5 | 
             
            AllCops:
         | 
| 2 6 | 
             
              Include:
         | 
| 3 7 | 
             
                - Gemfile
         | 
| 4 8 | 
             
                - Guardfile
         | 
| 5 9 | 
             
                - Rakefile
         | 
| 10 | 
            +
                - bin/howzit
         | 
| 11 | 
            +
                - lib/**/*.rb
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            Style/StringLiterals:
         | 
| 14 | 
            +
              Enabled: true
         | 
| 15 | 
            +
              EnforcedStyle: single_quotes
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            Style/StringLiteralsInInterpolation:
         | 
| 18 | 
            +
              Enabled: true
         | 
| 19 | 
            +
              EnforcedStyle: single_quotes
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            Layout/LineLength:
         | 
| 22 | 
            +
              Max: 120
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            Metrics/MethodLength:
         | 
| 25 | 
            +
              Max: 40
         | 
| 6 26 |  | 
| 7 27 | 
             
            Metrics/BlockLength:
         | 
| 28 | 
            +
              Max: 40
         | 
| 8 29 | 
             
              Exclude:
         | 
| 9 30 | 
             
                - Rakefile
         | 
| 10 31 | 
             
                - bin/howzit
         | 
| 11 32 | 
             
                - lib/*.rb
         | 
| 12 33 |  | 
| 34 | 
            +
            Metrics/ClassLength:
         | 
| 35 | 
            +
              Max: 300
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            Metrics/CyclomaticComplexity:
         | 
| 38 | 
            +
              Max: 10
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            Metrics/PerceivedComplexity:
         | 
| 41 | 
            +
              Max: 30
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            Metrics/AbcSize:
         | 
| 44 | 
            +
              Max: 45
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            Metrics/CyclomaticComplexity:
         | 
| 47 | 
            +
              Max: 15
         | 
| 48 | 
            +
             | 
| 13 49 | 
             
            Style/RegexpLiteral:
         | 
| 14 50 | 
             
              Exclude:
         | 
| 15 51 | 
             
                - Guardfile
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    
    
        data/Gemfile
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -1,3 +1,4 @@ | |
| 1 | 
            +
             | 
| 1 2 | 
             
            # Howzit
         | 
| 2 3 |  | 
| 3 4 | 
             
            [](https://rubygems.org/gems/howzit)
         | 
| @@ -8,8 +9,6 @@ A command-line reference tool for tracking project build systems | |
| 8 9 |  | 
| 9 10 | 
             
            Howzit is a tool that allows you to keep Markdown-formatted notes about a project's tools and procedures. It functions as an easy lookup for notes about a particular task, as well as a task runner to automatically execute appropriate commands.
         | 
| 10 11 |  | 
| 11 | 
            -
            <!--README-->
         | 
| 12 | 
            -
             | 
| 13 12 | 
             
            ## Features
         | 
| 14 13 |  | 
| 15 14 | 
             
            - Match topic titles with any portion of title
         | 
| @@ -55,8 +54,6 @@ If you run into permission errors using the above command, you'll need to use `g | |
| 55 54 |  | 
| 56 55 | 
             
            This project is licensed under the MIT License - see the [LICENSE.txt](LICENSE.txt) file for details.
         | 
| 57 56 |  | 
| 58 | 
            -
            <!--END README-->
         | 
| 59 | 
            -
             | 
| 60 57 | 
             
            ## Warranty
         | 
| 61 58 |  | 
| 62 59 | 
             
            This software is provided "as is" and without any express or
         | 
| @@ -74,6 +71,7 @@ purpose. | |
| 74 71 | 
             
            [RubyDoc]: http://www.rubydoc.info/gems/howzit
         | 
| 75 72 | 
             
            [Omniref]: https://www.omniref.com/ruby/gems/howzit
         | 
| 76 73 |  | 
| 74 | 
            +
             | 
| 77 75 | 
             
            ## Development and Testing
         | 
| 78 76 |  | 
| 79 77 | 
             
            ### Source Code
         | 
| @@ -143,3 +141,4 @@ To submit a patch: | |
| 143 141 | 
             
            5. Push to the branch (`git push origin my-new-feature`).
         | 
| 144 142 | 
             
            6. Create a new Pull Request.
         | 
| 145 143 |  | 
| 144 | 
            +
             | 
    
        data/Rakefile
    CHANGED
    
    | @@ -76,4 +76,35 @@ task :dockertest, :version, :login do |_, args| | |
| 76 76 | 
             
              # puts commit&.empty? ? "Error commiting Docker tag #{img}" : "Committed Docker tag #{img}"
         | 
| 77 77 | 
             
            end
         | 
| 78 78 |  | 
| 79 | 
            +
            desc 'Alias for build'
         | 
| 79 80 | 
             
            task package: :build
         | 
| 81 | 
            +
             | 
| 82 | 
            +
            desc 'Bump incremental version number'
         | 
| 83 | 
            +
            task :bump, :type do |_, args|
         | 
| 84 | 
            +
              args.with_defaults(type: 'inc')
         | 
| 85 | 
            +
              version_file = 'lib/howzit/version.rb'
         | 
| 86 | 
            +
              content = IO.read(version_file)
         | 
| 87 | 
            +
              content.sub!(/VERSION = '(?<major>\d+)\.(?<minor>\d+)\.(?<inc>\d+)(?<pre>\S+)?'/) do
         | 
| 88 | 
            +
                m = Regexp.last_match
         | 
| 89 | 
            +
                major = m['major'].to_i
         | 
| 90 | 
            +
                minor = m['minor'].to_i
         | 
| 91 | 
            +
                inc = m['inc'].to_i
         | 
| 92 | 
            +
                pre = m['pre']
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                case args[:type]
         | 
| 95 | 
            +
                when /^maj/
         | 
| 96 | 
            +
                  major += 1
         | 
| 97 | 
            +
                  minor = 0
         | 
| 98 | 
            +
                  inc = 0
         | 
| 99 | 
            +
                when /^min/
         | 
| 100 | 
            +
                  minor += 1
         | 
| 101 | 
            +
                  inc = 0
         | 
| 102 | 
            +
                else
         | 
| 103 | 
            +
                  inc += 1
         | 
| 104 | 
            +
                end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                $stdout.puts "At version #{major}.#{minor}.#{inc}#{pre}"
         | 
| 107 | 
            +
                "VERSION = '#{major}.#{minor}.#{inc}#{pre}'"
         | 
| 108 | 
            +
              end
         | 
| 109 | 
            +
              File.open(version_file, 'w+') { |f| f.puts content }
         | 
| 110 | 
            +
            end
         | 
    
        data/lib/howzit/buildnote.rb
    CHANGED
    
    | @@ -69,6 +69,7 @@ module Howzit | |
| 69 69 | 
             
                ##
         | 
| 70 70 | 
             
                def find_topic(term = nil)
         | 
| 71 71 | 
             
                  return @topics if term.nil?
         | 
| 72 | 
            +
             | 
| 72 73 | 
             
                  @topics.filter do |topic|
         | 
| 73 74 | 
             
                    rx = term.to_rx
         | 
| 74 75 | 
             
                    topic.title.downcase.sub(/ *\(.*?\) *$/, '') =~ rx
         | 
| @@ -114,7 +115,7 @@ module Howzit | |
| 114 115 | 
             
                ## @return     [Array] array of topic titles
         | 
| 115 116 | 
             
                ##
         | 
| 116 117 | 
             
                def list_topics
         | 
| 117 | 
            -
                  @topics.map | 
| 118 | 
            +
                  @topics.map(&:title)
         | 
| 118 119 | 
             
                end
         | 
| 119 120 |  | 
| 120 121 | 
             
                ##
         | 
| @@ -360,19 +361,21 @@ module Howzit | |
| 360 361 | 
             
                ##
         | 
| 361 362 | 
             
                def ensure_requirements(template)
         | 
| 362 363 | 
             
                  t_leader = Util.read_file(template).split(/^#/)[0].strip
         | 
| 363 | 
            -
                   | 
| 364 | 
            -
             | 
| 365 | 
            -
             | 
| 366 | 
            -
             | 
| 367 | 
            -
             | 
| 368 | 
            -
             | 
| 369 | 
            -
             | 
| 370 | 
            -
             | 
| 371 | 
            -
             | 
| 372 | 
            -
             | 
| 373 | 
            -
             | 
| 374 | 
            -
                       | 
| 375 | 
            -
                     | 
| 364 | 
            +
                  return unless t_leader.length.positive?
         | 
| 365 | 
            +
             | 
| 366 | 
            +
                  t_meta = t_leader.get_metadata
         | 
| 367 | 
            +
             | 
| 368 | 
            +
                  return unless t_meta.key?('required')
         | 
| 369 | 
            +
             | 
| 370 | 
            +
                  required = t_meta['required'].strip.split(/\s*,\s*/)
         | 
| 371 | 
            +
                  required.each do |req|
         | 
| 372 | 
            +
                    next if @metadata.keys.include?(req.downcase)
         | 
| 373 | 
            +
             | 
| 374 | 
            +
                    Howzit.console.error %({bRw}ERROR:{xbr} Missing required metadata key from template '{bw}#{File.basename(
         | 
| 375 | 
            +
                      template, '.md'
         | 
| 376 | 
            +
                    )}{xr}'{x}).c
         | 
| 377 | 
            +
                    Howzit.console.error %({br}Please define {by}#{req.downcase}{xr} in build notes{x}).c
         | 
| 378 | 
            +
                    Process.exit 1
         | 
| 376 379 | 
             
                  end
         | 
| 377 380 | 
             
                end
         | 
| 378 381 |  | 
| @@ -388,7 +391,7 @@ module Howzit | |
| 388 391 | 
             
                  subtopics = nil
         | 
| 389 392 |  | 
| 390 393 | 
             
                  if template =~ /\[(.*?)\]$/
         | 
| 391 | 
            -
                    subtopics = Regexp.last_match[1].split(/\s*\|\s*/).map { |t| t.gsub(/\*/, '.*?')}
         | 
| 394 | 
            +
                    subtopics = Regexp.last_match[1].split(/\s*\|\s*/).map { |t| t.gsub(/\*/, '.*?') }
         | 
| 392 395 | 
             
                    template.sub!(/\[.*?\]$/, '').strip
         | 
| 393 396 | 
             
                  end
         | 
| 394 397 |  | 
| @@ -640,11 +643,10 @@ module Howzit | |
| 640 643 | 
             
                    Howzit.has_read_upstream = true
         | 
| 641 644 | 
             
                  end
         | 
| 642 645 |  | 
| 643 | 
            -
                   | 
| 644 | 
            -
                    Howzit.console.error("{br}Note file found but no topics detected in #{note_file}{x}".c)
         | 
| 645 | 
            -
                    Process.exit 1
         | 
| 646 | 
            -
                  end
         | 
| 646 | 
            +
                  return unless note_file && @topics.empty?
         | 
| 647 647 |  | 
| 648 | 
            +
                  Howzit.console.error("{br}Note file found but no topics detected in #{note_file}{x}".c)
         | 
| 649 | 
            +
                  Process.exit 1
         | 
| 648 650 | 
             
                end
         | 
| 649 651 |  | 
| 650 652 | 
             
                ##
         | 
| @@ -704,7 +706,7 @@ module Howzit | |
| 704 706 | 
             
                             new_topic.print_out({ single: single })
         | 
| 705 707 | 
             
                           end
         | 
| 706 708 |  | 
| 707 | 
            -
                  output.nil? ? '' : output.join("\n")
         | 
| 709 | 
            +
                  output.nil? ? '' : output.join("\n\n")
         | 
| 708 710 | 
             
                end
         | 
| 709 711 |  | 
| 710 712 | 
             
                ##
         | 
| @@ -782,7 +784,7 @@ module Howzit | |
| 782 784 | 
             
                        when :all
         | 
| 783 785 | 
             
                          topic_matches.concat(matches)
         | 
| 784 786 | 
             
                        else
         | 
| 785 | 
            -
                          titles = matches.map | 
| 787 | 
            +
                          titles = matches.map(&:title)
         | 
| 786 788 | 
             
                          res = Prompt.choose(titles)
         | 
| 787 789 | 
             
                          old_matching = Howzit.options[:matching]
         | 
| 788 790 | 
             
                          Howzit.options[:matching] = 'exact'
         | 
    
        data/lib/howzit/colors.rb
    CHANGED
    
    | @@ -5,7 +5,7 @@ module Howzit | |
| 5 5 | 
             
              # Terminal output color functions.
         | 
| 6 6 | 
             
              module Color
         | 
| 7 7 | 
             
                # Regexp to match excape sequences
         | 
| 8 | 
            -
                ESCAPE_REGEX = /(?<=\[)(?:(?:(?:[349]|10)[0-9]|[0-9])?;?)+(?=m) | 
| 8 | 
            +
                ESCAPE_REGEX = /(?<=\[)(?:(?:(?:[349]|10)[0-9]|[0-9])?;?)+(?=m)/
         | 
| 9 9 |  | 
| 10 10 | 
             
                # All available color names. Available as methods and string extensions.
         | 
| 11 11 | 
             
                #
         | 
| @@ -113,7 +113,9 @@ module Howzit | |
| 113 113 | 
             
                    compiled = ''
         | 
| 114 114 | 
             
                    normalize_color.split('').each do |char|
         | 
| 115 115 | 
             
                      compiled += char
         | 
| 116 | 
            -
                       | 
| 116 | 
            +
                      if Color.attributes.include?(compiled.to_sym) || compiled =~ /^([fb]g?)?#([a-f0-9]{6})$/i
         | 
| 117 | 
            +
                        valid_color = compiled
         | 
| 118 | 
            +
                      end
         | 
| 117 119 | 
             
                    end
         | 
| 118 120 |  | 
| 119 121 | 
             
                    valid_color
         | 
| @@ -271,7 +273,12 @@ module Howzit | |
| 271 273 | 
             
                    input = input.join(' ') if input.is_a? Array
         | 
| 272 274 | 
             
                    fmt = input.gsub(/%/, '%%')
         | 
| 273 275 | 
             
                    fmt = fmt.gsub(/(?<!\\u|\$)\{(\w+)\}/i) do
         | 
| 274 | 
            -
                      Regexp.last_match(1) | 
| 276 | 
            +
                      m = Regexp.last_match(1)
         | 
| 277 | 
            +
                      if m =~ /^[wkglycmrWKGLYCMRdbuix]+$/
         | 
| 278 | 
            +
                        m.split('').map { |c| "%<#{c}>s" }.join('')
         | 
| 279 | 
            +
                      else
         | 
| 280 | 
            +
                        Regexp.last_match(0)
         | 
| 281 | 
            +
                      end
         | 
| 275 282 | 
             
                    end
         | 
| 276 283 |  | 
| 277 284 | 
             
                    colors = { w: white, k: black, g: green, l: blue,
         | 
| @@ -333,9 +340,28 @@ module Howzit | |
| 333 340 | 
             
                  module_eval(new_method)
         | 
| 334 341 | 
             
                end
         | 
| 335 342 |  | 
| 343 | 
            +
                ##
         | 
| 344 | 
            +
                ## Generate escape codes for hex colors
         | 
| 345 | 
            +
                ##
         | 
| 346 | 
            +
                ## @param      hex   [String] The hexadecimal color code
         | 
| 347 | 
            +
                ##
         | 
| 348 | 
            +
                ## @return     [String] ANSI escape string
         | 
| 349 | 
            +
                ##
         | 
| 350 | 
            +
                def rgb(hex)
         | 
| 351 | 
            +
                  is_bg = hex.match(/^bg?#/) ? true : false
         | 
| 352 | 
            +
                  hex_string = hex.sub(/^([fb]g?)?#/, '')
         | 
| 353 | 
            +
             | 
| 354 | 
            +
                  parts = hex_string.match(/(?<r>..)(?<g>..)(?<b>..)/)
         | 
| 355 | 
            +
                  t = []
         | 
| 356 | 
            +
                  %w[r g b].each do |e|
         | 
| 357 | 
            +
                    t << parts[e].hex
         | 
| 358 | 
            +
                  end
         | 
| 359 | 
            +
                  "\e[#{is_bg ? '48' : '38'};2;#{t.join(';')}m"
         | 
| 360 | 
            +
                end
         | 
| 361 | 
            +
             | 
| 336 362 | 
             
                # Regular expression that is used to scan for ANSI-sequences while
         | 
| 337 363 | 
             
                # uncoloring strings.
         | 
| 338 | 
            -
                COLORED_REGEXP = /\e\[(?:(?:[349]|10)[0-7]|[0-9])?m | 
| 364 | 
            +
                COLORED_REGEXP = /\e\[(?:(?:[349]|10)[0-7]|[0-9])?m/
         | 
| 339 365 |  | 
| 340 366 | 
             
                # Returns an uncolored version of the string, that is all
         | 
| 341 367 | 
             
                # ANSI-sequences are stripped from the string.
         | 
    
        data/lib/howzit/config.rb
    CHANGED
    
    | @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Howzit
         | 
| 2 4 | 
             
              # Config Class
         | 
| 3 5 | 
             
              class Config
         | 
| @@ -95,7 +97,7 @@ module Howzit | |
| 95 97 | 
             
                def should_ignore(filename)
         | 
| 96 98 | 
             
                  return false unless File.exist?(ignore_file)
         | 
| 97 99 |  | 
| 98 | 
            -
                  @ignore_patterns ||= YAML. | 
| 100 | 
            +
                  @ignore_patterns ||= YAML.load(Util.read_file(ignore_file))
         | 
| 99 101 |  | 
| 100 102 | 
             
                  ignore = false
         | 
| 101 103 |  | 
    
        data/lib/howzit/prompt.rb
    CHANGED
    
    
    
        data/lib/howzit/stringutils.rb
    CHANGED
    
    | @@ -103,7 +103,7 @@ module Howzit | |
| 103 103 |  | 
| 104 104 | 
             
                # Just strip out color codes when requested
         | 
| 105 105 | 
             
                def uncolor
         | 
| 106 | 
            -
                  gsub(/\e\[[\d;]+m/, '').gsub(/\e\]1337;SetMark/,'')
         | 
| 106 | 
            +
                  gsub(/\e\[[\d;]+m/, '').gsub(/\e\]1337;SetMark/, '')
         | 
| 107 107 | 
             
                end
         | 
| 108 108 |  | 
| 109 109 | 
             
                # Wrap text at a specified width.
         | 
| @@ -277,7 +277,7 @@ module Howzit | |
| 277 277 | 
             
                def extract_metadata
         | 
| 278 278 | 
             
                  if File.exist?(self)
         | 
| 279 279 | 
             
                    leader = Util.read_file(self).split(/^#/)[0].strip
         | 
| 280 | 
            -
                    leader.length  | 
| 280 | 
            +
                    leader.length.positive? ? leader.get_metadata : {}
         | 
| 281 281 | 
             
                  else
         | 
| 282 282 | 
             
                    {}
         | 
| 283 283 | 
             
                  end
         | 
| @@ -361,11 +361,11 @@ module Howzit | |
| 361 361 |  | 
| 362 362 | 
             
                  case Howzit.options[:header_format]
         | 
| 363 363 | 
             
                  when :block
         | 
| 364 | 
            -
                    Color.template("#{options[:color]}\u{258C}#{title}#{should_mark_iterm? && options[:mark] ? iterm_marker : ''}{x}")
         | 
| 364 | 
            +
                    Color.template("\n\n#{options[:color]}\u{258C}#{title}#{should_mark_iterm? && options[:mark] ? iterm_marker : ''}{x}")
         | 
| 365 365 | 
             
                  else
         | 
| 366 366 | 
             
                    cols = TTY::Screen.columns
         | 
| 367 367 |  | 
| 368 | 
            -
                    cols = Howzit.options[:wrap] if  | 
| 368 | 
            +
                    cols = Howzit.options[:wrap] if Howzit.options[:wrap].positive? && cols > Howzit.options[:wrap]
         | 
| 369 369 | 
             
                    title = Color.template("#{options[:border]}#{options[:hr] * 2}( #{options[:color]}#{title}#{options[:border]} )")
         | 
| 370 370 |  | 
| 371 371 | 
             
                    tail = if should_mark_iterm?
         | 
| @@ -373,7 +373,7 @@ module Howzit | |
| 373 373 | 
             
                           else
         | 
| 374 374 | 
             
                             options[:hr] * (cols - title.uncolor.length)
         | 
| 375 375 | 
             
                           end
         | 
| 376 | 
            -
                    Color.template("#{title}#{tail}{x}")
         | 
| 376 | 
            +
                    Color.template("\n\n#{title}#{tail}{x}")
         | 
| 377 377 | 
             
                  end
         | 
| 378 378 | 
             
                end
         | 
| 379 379 | 
             
              end
         | 
    
        data/lib/howzit/task.rb
    CHANGED
    
    | @@ -39,7 +39,7 @@ module Howzit | |
| 39 39 | 
             
                ## @return     [String] description
         | 
| 40 40 | 
             
                ##
         | 
| 41 41 | 
             
                def inspect
         | 
| 42 | 
            -
                  %(<#Howzit::Task @type=:#{@type} @title="#{@title}" @arguments=#{@arguments} @block?=#{@action.split(/\n/).count > 1}>)
         | 
| 42 | 
            +
                  %(<#Howzit::Task @type=:#{@type} @title="#{@title}" @action="#{@action}" @arguments=#{@arguments} @block?=#{@action.split(/\n/).count > 1}>)
         | 
| 43 43 | 
             
                end
         | 
| 44 44 |  | 
| 45 45 | 
             
                ##
         | 
| @@ -95,7 +95,8 @@ module Howzit | |
| 95 95 | 
             
                def run_run
         | 
| 96 96 | 
             
                  title = Howzit.options[:show_all_code] ? @action : @title
         | 
| 97 97 | 
             
                  Howzit.console.info("#{@prefix}{bg}Running {bw}#{title}{x}".c)
         | 
| 98 | 
            -
                   | 
| 98 | 
            +
                  ENV['HOWZIT_SCRIPTS'] = File.expand_path('~/.config/howzit/scripts')
         | 
| 99 | 
            +
                  system(@action)
         | 
| 99 100 | 
             
                end
         | 
| 100 101 |  | 
| 101 102 | 
             
                ##
         | 
| @@ -105,7 +106,7 @@ module Howzit | |
| 105 106 | 
             
                  title = Howzit.options[:show_all_code] ? @action : @title
         | 
| 106 107 | 
             
                  Howzit.console.info("#{@prefix}{bg}Copied {bw}#{title}{bg} to clipboard{x}".c)
         | 
| 107 108 | 
             
                  Util.os_copy(@action)
         | 
| 108 | 
            -
                   | 
| 109 | 
            +
                  true
         | 
| 109 110 | 
             
                end
         | 
| 110 111 |  | 
| 111 112 | 
             
                ##
         | 
    
        data/lib/howzit/topic.rb
    CHANGED
    
    | @@ -56,15 +56,28 @@ module Howzit | |
| 56 56 | 
             
                  @title =~ /#{term}/i || @content =~ /#{term}/i
         | 
| 57 57 | 
             
                end
         | 
| 58 58 |  | 
| 59 | 
            +
                def ask_task(task)
         | 
| 60 | 
            +
                  note = if task.type == :include
         | 
| 61 | 
            +
                           task_count = Howzit.buildnote.find_topic(task.action)[0].tasks.count
         | 
| 62 | 
            +
                           " (#{task_count} tasks)"
         | 
| 63 | 
            +
                         else
         | 
| 64 | 
            +
                           ''
         | 
| 65 | 
            +
                         end
         | 
| 66 | 
            +
                  q = %({bg}#{task.type.to_s.capitalize} {xw}"{bw}#{task.title}{xw}"#{note}{x}).c
         | 
| 67 | 
            +
                  Prompt.yn(q, default: task.default)
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                def check_cols
         | 
| 71 | 
            +
                  TTY::Screen.columns > 60 ? 60 : TTY::Screen.columns
         | 
| 72 | 
            +
                rescue StandardError
         | 
| 73 | 
            +
                  60
         | 
| 74 | 
            +
                end
         | 
| 75 | 
            +
             | 
| 59 76 | 
             
                # Handle run command, execute directives in topic
         | 
| 60 77 | 
             
                def run(nested: false)
         | 
| 61 78 | 
             
                  output = []
         | 
| 62 79 |  | 
| 63 | 
            -
                  cols =  | 
| 64 | 
            -
                    TTY::Screen.columns > 60 ? 60 : TTY::Screen.columns
         | 
| 65 | 
            -
                  rescue StandardError
         | 
| 66 | 
            -
                    60
         | 
| 67 | 
            -
                  end
         | 
| 80 | 
            +
                  cols = check_cols
         | 
| 68 81 |  | 
| 69 82 | 
             
                  if @tasks.count.positive?
         | 
| 70 83 | 
             
                    unless @prereqs.empty?
         | 
| @@ -75,18 +88,8 @@ module Howzit | |
| 75 88 | 
             
                    end
         | 
| 76 89 |  | 
| 77 90 | 
             
                    @tasks.each do |task|
         | 
| 78 | 
            -
                      if task.optional || Howzit.options[:ask]
         | 
| 79 | 
            -
                        note = if task.type == :include
         | 
| 80 | 
            -
                                 task_count = Howzit.buildnote.find_topic(task.action)[0].tasks.count
         | 
| 81 | 
            -
                                 " (#{task_count} tasks)"
         | 
| 82 | 
            -
                               else
         | 
| 83 | 
            -
                                 ''
         | 
| 84 | 
            -
                               end
         | 
| 85 | 
            -
                        q = %({bg}#{task.type.to_s.capitalize} {xw}"{bw}#{task.title}{xw}"#{note}{x}).c
         | 
| 86 | 
            -
                        res = Prompt.yn(q, default: task.default)
         | 
| 87 | 
            -
                        next unless res
         | 
| 91 | 
            +
                      next if (task.optional || Howzit.options[:ask]) && !ask_task(task)
         | 
| 88 92 |  | 
| 89 | 
            -
                      end
         | 
| 90 93 | 
             
                      run_output, total, success = task.run
         | 
| 91 94 |  | 
| 92 95 | 
             
                      output.concat(run_output)
         | 
| @@ -123,6 +126,116 @@ module Howzit | |
| 123 126 | 
             
                  output
         | 
| 124 127 | 
             
                end
         | 
| 125 128 |  | 
| 129 | 
            +
                def title_option(color, topic, keys, opt)
         | 
| 130 | 
            +
                  option = colored_option(color, topic, keys)
         | 
| 131 | 
            +
                  "#{opt[:single] ? 'From' : 'Include'} #{topic.title}#{option}:"
         | 
| 132 | 
            +
                end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                def colored_option(color, topic, keys)
         | 
| 135 | 
            +
                  if topic.tasks.empty?
         | 
| 136 | 
            +
                    ''
         | 
| 137 | 
            +
                  else
         | 
| 138 | 
            +
                    optional = keys[:optional] =~ /[?!]+/ ? true : false
         | 
| 139 | 
            +
                    default = keys[:optional] =~ /!/ ? false : true
         | 
| 140 | 
            +
                    if optional
         | 
| 141 | 
            +
                      colored_yn(color, default)
         | 
| 142 | 
            +
                    else
         | 
| 143 | 
            +
                      ''
         | 
| 144 | 
            +
                    end
         | 
| 145 | 
            +
                  end
         | 
| 146 | 
            +
                end
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                def colored_yn(color, default)
         | 
| 149 | 
            +
                  if default
         | 
| 150 | 
            +
                    " {xKk}[{gbK}Y{xKk}/{dbwK}n{xKk}]{x}#{color}".c
         | 
| 151 | 
            +
                  else
         | 
| 152 | 
            +
                    " {xKk}[{dbwK}y{xKk}/{bgK}N{xKk}]{x}#{color}".c
         | 
| 153 | 
            +
                  end
         | 
| 154 | 
            +
                end
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                ##
         | 
| 157 | 
            +
                ## Handle an include statement
         | 
| 158 | 
            +
                ##
         | 
| 159 | 
            +
                ## @param      keys  [Hash] The symbolized keys and values from the regex
         | 
| 160 | 
            +
                ##                   that found the statement
         | 
| 161 | 
            +
                ## @param      opt   [Hash] Options
         | 
| 162 | 
            +
                ##
         | 
| 163 | 
            +
                def process_include(keys, opt)
         | 
| 164 | 
            +
                  output = []
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                  if keys[:action] =~ / *\[(.*?)\] *$/
         | 
| 167 | 
            +
                    Howzit.named_arguments = @named_args
         | 
| 168 | 
            +
                    Howzit.arguments = Regexp.last_match(1).split(/ *, */).map!(&:render_arguments)
         | 
| 169 | 
            +
                  end
         | 
| 170 | 
            +
             | 
| 171 | 
            +
                  matches = Howzit.buildnote.find_topic(keys[:action].sub(/ *\[.*?\] *$/, ''))
         | 
| 172 | 
            +
             | 
| 173 | 
            +
                  return [] if matches.empty?
         | 
| 174 | 
            +
             | 
| 175 | 
            +
                  topic = matches[0]
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                  rule = '{kKd}'
         | 
| 178 | 
            +
                  color = '{Kyd}'
         | 
| 179 | 
            +
                  title = title_option(color, topic, keys, opt)
         | 
| 180 | 
            +
                  options = { color: color, hr: '.', border: rule }
         | 
| 181 | 
            +
             | 
| 182 | 
            +
                  output.push("#{'> ' * @nest_level}#{title}".format_header(options)) unless Howzit.inclusions.include?(topic)
         | 
| 183 | 
            +
             | 
| 184 | 
            +
                  if opt[:single] && Howzit.inclusions.include?(topic)
         | 
| 185 | 
            +
                    output.push("#{'> ' * @nest_level}#{title} included above".format_header(options))
         | 
| 186 | 
            +
                  elsif opt[:single]
         | 
| 187 | 
            +
                    @nest_level += 1
         | 
| 188 | 
            +
             | 
| 189 | 
            +
                    output.concat(topic.print_out({ single: true, header: false }))
         | 
| 190 | 
            +
                    output.push("#{'> ' * @nest_level}...".format_header(options))
         | 
| 191 | 
            +
                    @nest_level -= 1
         | 
| 192 | 
            +
                  end
         | 
| 193 | 
            +
                  Howzit.inclusions.push(topic)
         | 
| 194 | 
            +
             | 
| 195 | 
            +
                  output
         | 
| 196 | 
            +
                end
         | 
| 197 | 
            +
             | 
| 198 | 
            +
                def color_directive_yn(keys)
         | 
| 199 | 
            +
                  optional, default = define_optional(keys[:optional])
         | 
| 200 | 
            +
                  if optional
         | 
| 201 | 
            +
                    default ? ' {xk}[{g}Y{xk}/{dbw}n{xk}]{x}'.c : ' {xk}[{dbw}y{xk}/{g}N{xk}]{x}'.c
         | 
| 202 | 
            +
                  else
         | 
| 203 | 
            +
                    ''
         | 
| 204 | 
            +
                  end
         | 
| 205 | 
            +
                end
         | 
| 206 | 
            +
             | 
| 207 | 
            +
                def process_directive(keys)
         | 
| 208 | 
            +
                  cmd = keys[:cmd]
         | 
| 209 | 
            +
                  obj = keys[:action]
         | 
| 210 | 
            +
                  title = keys[:title].empty? ? obj : keys[:title].strip
         | 
| 211 | 
            +
                  title = Howzit.options[:show_all_code] ? obj : title
         | 
| 212 | 
            +
                  option = color_directive_yn(keys)
         | 
| 213 | 
            +
                  icon = case cmd
         | 
| 214 | 
            +
                         when 'run'
         | 
| 215 | 
            +
                           "\u{25B6}"
         | 
| 216 | 
            +
                         when 'copy'
         | 
| 217 | 
            +
                           "\u{271A}"
         | 
| 218 | 
            +
                         when /open|url/
         | 
| 219 | 
            +
                           "\u{279A}"
         | 
| 220 | 
            +
                         end
         | 
| 221 | 
            +
             | 
| 222 | 
            +
                  "{bmK}#{icon} {bwK}#{title.preserve_escapes}{x}#{option}".c
         | 
| 223 | 
            +
                end
         | 
| 224 | 
            +
             | 
| 225 | 
            +
                def define_optional(optional)
         | 
| 226 | 
            +
                  is_optional = optional =~ /[?!]+/ ? true : false
         | 
| 227 | 
            +
                  default = optional =~ /!/ ? false : true
         | 
| 228 | 
            +
                  [is_optional, default]
         | 
| 229 | 
            +
                end
         | 
| 230 | 
            +
             | 
| 231 | 
            +
                def title_code_block(keys)
         | 
| 232 | 
            +
                  if keys[:title].length.positive?
         | 
| 233 | 
            +
                    "Block: #{keys[:title]}#{color_directive_yn(keys)}"
         | 
| 234 | 
            +
                  else
         | 
| 235 | 
            +
                    "Code Block#{color_directive_yn(keys)}"
         | 
| 236 | 
            +
                  end
         | 
| 237 | 
            +
                end
         | 
| 238 | 
            +
             | 
| 126 239 | 
             
                # Output a topic with fancy title and bright white text.
         | 
| 127 240 | 
             
                #
         | 
| 128 241 | 
             
                # @param      options  [Hash] The options
         | 
| @@ -139,99 +252,23 @@ module Howzit | |
| 139 252 | 
             
                    output.push('')
         | 
| 140 253 | 
             
                  end
         | 
| 141 254 | 
             
                  topic = @content.dup
         | 
| 142 | 
            -
                   | 
| 255 | 
            +
                  unless Howzit.options[:show_all_code]
         | 
| 256 | 
            +
                    topic.gsub!(/(?mix)^(`{3,})run([?!]*)\s*
         | 
| 257 | 
            +
                                ([^\n]*)[\s\S]*?\n\1\s*$/, '@@@run\2 \3')
         | 
| 258 | 
            +
                  end
         | 
| 143 259 | 
             
                  topic.split(/\n/).each do |l|
         | 
| 144 260 | 
             
                    case l
         | 
| 145 261 | 
             
                    when /@(before|after|prereq|end)/
         | 
| 146 262 | 
             
                      next
         | 
| 147 | 
            -
                    when /@include(?<optional>[!?]{1,2})?\((?<action>[ | 
| 148 | 
            -
                       | 
| 149 | 
            -
             | 
| 150 | 
            -
                      if m[:action] =~ / *\[(.*?)\] *$/
         | 
| 151 | 
            -
                        Howzit.named_arguments = @named_args
         | 
| 152 | 
            -
                        Howzit.arguments = Regexp.last_match(1).split(/ *, */).map!(&:render_arguments)
         | 
| 153 | 
            -
                      end
         | 
| 154 | 
            -
             | 
| 155 | 
            -
                      matches = Howzit.buildnote.find_topic(m[:action].sub(/ *\[.*?\] *$/, ''))
         | 
| 156 | 
            -
             | 
| 157 | 
            -
                      unless matches.empty?
         | 
| 158 | 
            -
                        i_topic = matches[0]
         | 
| 159 | 
            -
             | 
| 160 | 
            -
                        rule = '{kKd}'
         | 
| 161 | 
            -
                        color = '{Kyd}'
         | 
| 162 | 
            -
                        option = if i_topic.tasks.empty?
         | 
| 163 | 
            -
                                   ''
         | 
| 164 | 
            -
                                 else
         | 
| 165 | 
            -
                                   optional = m[:optional] =~ /[?!]+/ ? true : false
         | 
| 166 | 
            -
                                   default = m[:optional] =~ /!/ ? false : true
         | 
| 167 | 
            -
                                   if optional
         | 
| 168 | 
            -
                                     default ? " {xKk}[{gbK}Y{xKk}/{dbwK}n{xKk}]{x}#{color}".c : " {xKk}[{dbwK}y{xKk}/{bgK}N{xKk}]{x}#{color}".c
         | 
| 169 | 
            -
                                   else
         | 
| 170 | 
            -
                                     ''
         | 
| 171 | 
            -
                                   end
         | 
| 172 | 
            -
                                 end
         | 
| 173 | 
            -
                        title = "#{opt[:single] ? 'From' : 'Include'} #{i_topic.title}#{option}:"
         | 
| 174 | 
            -
                        options = { color: color, hr: '.', border: rule }
         | 
| 175 | 
            -
                        unless Howzit.inclusions.include?(i_topic)
         | 
| 176 | 
            -
                          output.push("#{'> ' * @nest_level}#{title}".format_header(options))
         | 
| 177 | 
            -
                        end
         | 
| 178 | 
            -
             | 
| 179 | 
            -
                        if opt[:single] && Howzit.inclusions.include?(i_topic)
         | 
| 180 | 
            -
                          output.push("#{'> ' * @nest_level}#{title} included above".format_header(options))
         | 
| 181 | 
            -
                        elsif opt[:single]
         | 
| 182 | 
            -
                          @nest_level += 1
         | 
| 183 | 
            -
             | 
| 184 | 
            -
                          output.concat(i_topic.print_out({ single: true, header: false }))
         | 
| 185 | 
            -
                          output.push("#{'> ' * @nest_level}...".format_header(options))
         | 
| 186 | 
            -
                          @nest_level -= 1
         | 
| 187 | 
            -
                        end
         | 
| 188 | 
            -
                        Howzit.inclusions.push(i_topic)
         | 
| 189 | 
            -
                      end
         | 
| 263 | 
            +
                    when /@include(?<optional>[!?]{1,2})?\((?<action>[^)]+)\)/
         | 
| 264 | 
            +
                      output.concat(process_include(Regexp.last_match.named_captures.symbolize_keys, opt))
         | 
| 190 265 | 
             
                    when /@(?<cmd>run|copy|open|url)(?<optional>[?!]{1,2})?\((?<action>.*?)\) *(?<title>.*?)$/
         | 
| 191 | 
            -
                       | 
| 192 | 
            -
                      cmd = m[:cmd]
         | 
| 193 | 
            -
                      obj = m[:action]
         | 
| 194 | 
            -
                      title = m[:title].empty? ? obj : m[:title].strip
         | 
| 195 | 
            -
                      title = Howzit.options[:show_all_code] ? obj : title
         | 
| 196 | 
            -
                      optional = m[:optional] =~ /[?!]+/ ? true : false
         | 
| 197 | 
            -
                      default = m[:optional] =~ /!/ ? false : true
         | 
| 198 | 
            -
                      option = if optional
         | 
| 199 | 
            -
                                 default ? ' {xk}[{g}Y{xk}/{dbw}n{xk}]{x}'.c : ' {xk}[{dbw}y{xk}/{g}N{xk}]{x}'.c
         | 
| 200 | 
            -
                               else
         | 
| 201 | 
            -
                                 ''
         | 
| 202 | 
            -
                               end
         | 
| 203 | 
            -
                      icon = case cmd
         | 
| 204 | 
            -
                             when 'run'
         | 
| 205 | 
            -
                               "\u{25B6}"
         | 
| 206 | 
            -
                             when 'copy'
         | 
| 207 | 
            -
                               "\u{271A}"
         | 
| 208 | 
            -
                             when /open|url/
         | 
| 209 | 
            -
                               "\u{279A}"
         | 
| 210 | 
            -
                             end
         | 
| 211 | 
            -
             | 
| 212 | 
            -
                      output.push("{bmK}#{icon} {bwK}#{title.preserve_escapes}{x}#{option}".c)
         | 
| 266 | 
            +
                      output.push(process_directive(Regexp.last_match.named_captures.symbolize_keys))
         | 
| 213 267 | 
             
                    when /(?<fence>`{3,})run(?<optional>[!?]{1,2})? *(?<title>.*?)$/i
         | 
| 214 | 
            -
                       | 
| 215 | 
            -
                      optional = m[:optional] =~ /[?!]+/ ? true : false
         | 
| 216 | 
            -
                      default = m[:optional] =~ /!/ ? false : true
         | 
| 217 | 
            -
                      option = if optional
         | 
| 218 | 
            -
                                 default ? ' {xk}[{g}Y{xk}/{dbw}n{xk}]{x}'.c : ' {xk}[{dbw}y{xk}/{g}N{xk}]{x}'.c
         | 
| 219 | 
            -
                               else
         | 
| 220 | 
            -
                                 ''
         | 
| 221 | 
            -
                               end
         | 
| 222 | 
            -
                      desc = m[:title].length.positive? ? "Block: #{m[:title]}#{option}" : "Code Block#{option}"
         | 
| 268 | 
            +
                      desc = title_code_block(Regexp.last_match.named_captures.symbolize_keys)
         | 
| 223 269 | 
             
                      output.push("{bmK}\u{25B6} {bwK}#{desc}{x}\n```".c)
         | 
| 224 270 | 
             
                    when /@@@run(?<optional>[!?]{1,2})? *(?<title>.*?)$/i
         | 
| 225 | 
            -
                       | 
| 226 | 
            -
                      optional = m[:optional] =~ /[?!]+/ ? true : false
         | 
| 227 | 
            -
                      default = m[:optional] =~ /!/ ? false : true
         | 
| 228 | 
            -
                      option = if optional
         | 
| 229 | 
            -
                                 default ? ' {xk}[{g}Y{xk}/{dbw}n{xk}]{x}'.c : ' {xk}[{dbw}y{xk}/{g}N{xk}]{x}'.c
         | 
| 230 | 
            -
                               else
         | 
| 231 | 
            -
                                 ''
         | 
| 232 | 
            -
                               end
         | 
| 233 | 
            -
                      desc = m[:title].length.positive? ? "Block: #{m[:title]}#{option}" : "Code Block#{option}"
         | 
| 234 | 
            -
                      output.push("{bmK}\u{25B6} {bwK}#{desc}{x}".c)
         | 
| 271 | 
            +
                      output.push("{bmK}\u{25B6} {bwK}#{title_code_block(Regexp.last_match.named_captures.symbolize_keys)}{x}".c)
         | 
| 235 272 | 
             
                    else
         | 
| 236 273 | 
             
                      l.wrap!(Howzit.options[:wrap]) if Howzit.options[:wrap].positive?
         | 
| 237 274 | 
             
                      output.push(l)
         | 
| @@ -241,6 +278,45 @@ module Howzit | |
| 241 278 | 
             
                  output.push('').map(&:render_arguments)
         | 
| 242 279 | 
             
                end
         | 
| 243 280 |  | 
| 281 | 
            +
                include Comparable
         | 
| 282 | 
            +
                def <=>(other)
         | 
| 283 | 
            +
                  @title <=> other.title
         | 
| 284 | 
            +
                end
         | 
| 285 | 
            +
             | 
| 286 | 
            +
                def define_task_args(keys)
         | 
| 287 | 
            +
                  cmd = keys[:cmd]
         | 
| 288 | 
            +
                  obj = keys[:action]
         | 
| 289 | 
            +
                  title = keys[:title].nil? ? obj : keys[:title].strip
         | 
| 290 | 
            +
                  title = Howzit.options[:show_all_code] ? obj : title
         | 
| 291 | 
            +
                  task_args = { type: :include,
         | 
| 292 | 
            +
                                arguments: nil,
         | 
| 293 | 
            +
                                title: title,
         | 
| 294 | 
            +
                                action: obj,
         | 
| 295 | 
            +
                                parent: self }
         | 
| 296 | 
            +
                  case cmd
         | 
| 297 | 
            +
                  when /include/i
         | 
| 298 | 
            +
                    if title =~ /\[(.*?)\] *$/
         | 
| 299 | 
            +
                      Howzit.named_arguments = @named_args
         | 
| 300 | 
            +
                      args = Regexp.last_match(1).split(/ *, */).map(&:render_arguments)
         | 
| 301 | 
            +
                      Howzit.arguments = args
         | 
| 302 | 
            +
                      arguments
         | 
| 303 | 
            +
                      title.sub!(/ *\[.*?\] *$/, '')
         | 
| 304 | 
            +
                    end
         | 
| 305 | 
            +
             | 
| 306 | 
            +
                    task_args[:type] = :include
         | 
| 307 | 
            +
                    task_args[:arguments] = Howzit.named_arguments
         | 
| 308 | 
            +
                  when /run/i
         | 
| 309 | 
            +
                    task_args[:type] = :run
         | 
| 310 | 
            +
                  when /copy/i
         | 
| 311 | 
            +
                    task_args[:type] = :copy
         | 
| 312 | 
            +
                    task_args[:action] = Shellwords.escape(obj)
         | 
| 313 | 
            +
                  when /open|url/i
         | 
| 314 | 
            +
                    task_args[:type] = :open
         | 
| 315 | 
            +
                  end
         | 
| 316 | 
            +
             | 
| 317 | 
            +
                  task_args
         | 
| 318 | 
            +
                end
         | 
| 319 | 
            +
             | 
| 244 320 | 
             
                private
         | 
| 245 321 |  | 
| 246 322 | 
             
                ##
         | 
| @@ -264,8 +340,7 @@ module Howzit | |
| 264 340 | 
             
                    Howzit.named_arguments = @named_args
         | 
| 265 341 |  | 
| 266 342 | 
             
                    if c[:cmd].nil?
         | 
| 267 | 
            -
                      optional = c[:optional2] | 
| 268 | 
            -
                      default = c[:optional2] =~ /!/ ? false : true
         | 
| 343 | 
            +
                      optional, default = define_optional(c[:optional2])
         | 
| 269 344 | 
             
                      title = c[:title2].nil? ? '' : c[:title2].strip
         | 
| 270 345 | 
             
                      block = c[:block]&.strip
         | 
| 271 346 | 
             
                      runnable << Howzit::Task.new({ type: :block,
         | 
| @@ -275,63 +350,10 @@ module Howzit | |
| 275 350 | 
             
                                                   optional: optional,
         | 
| 276 351 | 
             
                                                   default: default)
         | 
| 277 352 | 
             
                    else
         | 
| 278 | 
            -
                       | 
| 279 | 
            -
                       | 
| 280 | 
            -
             | 
| 281 | 
            -
             | 
| 282 | 
            -
                      title = c[:title].nil? ? obj : c[:title].strip
         | 
| 283 | 
            -
                      title = Howzit.options[:show_all_code] ? obj : title
         | 
| 284 | 
            -
                      case cmd
         | 
| 285 | 
            -
                      when /include/i
         | 
| 286 | 
            -
                        # matches = Howzit.buildnote.find_topic(obj)
         | 
| 287 | 
            -
                        # unless matches.empty? || Howzit.inclusions.include?(matches[0].title)
         | 
| 288 | 
            -
                        #   tasks = matches[0].tasks.map do |inc|
         | 
| 289 | 
            -
                        #     Howzit.inclusions.push(matches[0].title)
         | 
| 290 | 
            -
                        #     inc.parent = matches[0]
         | 
| 291 | 
            -
                        #     inc
         | 
| 292 | 
            -
                        #   end
         | 
| 293 | 
            -
                        #   runnable.concat(tasks)
         | 
| 294 | 
            -
                        # end
         | 
| 295 | 
            -
                        args = []
         | 
| 296 | 
            -
                        if title =~ /\[(.*?)\] *$/
         | 
| 297 | 
            -
                          Howzit.named_arguments = @named_args
         | 
| 298 | 
            -
                          args = Regexp.last_match(1).split(/ *, */).map(&:render_arguments)
         | 
| 299 | 
            -
                          Howzit.arguments = args
         | 
| 300 | 
            -
                          arguments
         | 
| 301 | 
            -
                          title.sub!(/ *\[.*?\] *$/, '')
         | 
| 302 | 
            -
                        end
         | 
| 303 | 
            -
             | 
| 304 | 
            -
                        runnable << Howzit::Task.new({ type: :include,
         | 
| 305 | 
            -
                                                       arguments: Howzit.named_arguments,
         | 
| 306 | 
            -
                                                       title: title,
         | 
| 307 | 
            -
                                                       action: obj,
         | 
| 308 | 
            -
                                                       parent: self },
         | 
| 309 | 
            -
                                                     optional: optional,
         | 
| 310 | 
            -
                                                     default: default)
         | 
| 311 | 
            -
                      when /run/i
         | 
| 312 | 
            -
                        # warn "{bg}Running {bw}#{obj}{x}".c if Howzit.options[:log_level] < 2
         | 
| 313 | 
            -
                        runnable << Howzit::Task.new({ type: :run,
         | 
| 314 | 
            -
                                                       title: title,
         | 
| 315 | 
            -
                                                       action: obj,
         | 
| 316 | 
            -
                                                       parent: self },
         | 
| 317 | 
            -
                                                     optional: optional,
         | 
| 318 | 
            -
                                                     default: default)
         | 
| 319 | 
            -
                      when /copy/i
         | 
| 320 | 
            -
                        # warn "{bg}Copied {bw}#{obj}{bg} to clipboard{x}".c if Howzit.options[:log_level] < 2
         | 
| 321 | 
            -
                        runnable << Howzit::Task.new({ type: :copy,
         | 
| 322 | 
            -
                                                       title: title,
         | 
| 323 | 
            -
                                                       action: Shellwords.escape(obj),
         | 
| 324 | 
            -
                                                       parent: self },
         | 
| 325 | 
            -
                                                     optional: optional,
         | 
| 326 | 
            -
                                                     default: default)
         | 
| 327 | 
            -
                      when /open|url/i
         | 
| 328 | 
            -
                        runnable << Howzit::Task.new({ type: :open,
         | 
| 329 | 
            -
                                                       title: title,
         | 
| 330 | 
            -
                                                       action: obj,
         | 
| 331 | 
            -
                                                       parent: self },
         | 
| 332 | 
            -
                                                     optional: optional,
         | 
| 333 | 
            -
                                                     default: default)
         | 
| 334 | 
            -
                      end
         | 
| 353 | 
            +
                      optional, default = define_optional(c[:optional])
         | 
| 354 | 
            +
                      runnable << Howzit::Task.new(define_task_args(c),
         | 
| 355 | 
            +
                                                   optional: optional,
         | 
| 356 | 
            +
                                                   default: default)
         | 
| 335 357 | 
             
                    end
         | 
| 336 358 | 
             
                  end
         | 
| 337 359 |  | 
    
        data/lib/howzit/util.rb
    CHANGED
    
    | @@ -210,6 +210,33 @@ module Howzit | |
| 210 210 | 
             
                    end
         | 
| 211 211 | 
             
                  end
         | 
| 212 212 |  | 
| 213 | 
            +
                  ##
         | 
| 214 | 
            +
                  ## Platform-agnostic paste-from-clipboard
         | 
| 215 | 
            +
                  ##
         | 
| 216 | 
            +
                  def os_paste
         | 
| 217 | 
            +
                    os = RbConfig::CONFIG['target_os']
         | 
| 218 | 
            +
                    out = "{bg}Pasting from clipboard".c
         | 
| 219 | 
            +
                    case os
         | 
| 220 | 
            +
                    when /darwin.*/i
         | 
| 221 | 
            +
                      Howzit.console.debug("#{out} (macOS){x}".c)
         | 
| 222 | 
            +
                      `pbpaste`
         | 
| 223 | 
            +
                    when /mingw|mswin/i
         | 
| 224 | 
            +
                      Howzit.console.debug("#{out} (Windows){x}".c)
         | 
| 225 | 
            +
                      `cat /dev/clipboard`
         | 
| 226 | 
            +
                    else
         | 
| 227 | 
            +
                      if 'xsel'.available?
         | 
| 228 | 
            +
                        Howzit.console.debug("#{out} (Linux, xsel){x}".c)
         | 
| 229 | 
            +
                        `xsel --clipboard --output`
         | 
| 230 | 
            +
                      elsif 'xclip'.available?
         | 
| 231 | 
            +
                        Howzit.console.debug("#{out} (Linux, xclip){x}".c)
         | 
| 232 | 
            +
                        `xclip -selection clipboard -o`
         | 
| 233 | 
            +
                      else
         | 
| 234 | 
            +
                        Howzit.console.debug(out)
         | 
| 235 | 
            +
                        Howzit.console.warn('Unable to determine executable for clipboard.')
         | 
| 236 | 
            +
                      end
         | 
| 237 | 
            +
                    end
         | 
| 238 | 
            +
                  end
         | 
| 239 | 
            +
             | 
| 213 240 | 
             
                  ##
         | 
| 214 241 | 
             
                  ## Platform-agnostic open command
         | 
| 215 242 | 
             
                  ##
         | 
    
        data/lib/howzit/version.rb
    CHANGED
    
    
    
        data/lib/howzit.rb
    CHANGED
    
    | @@ -50,6 +50,7 @@ require 'tty/box' | |
| 50 50 | 
             
            module Howzit
         | 
| 51 51 | 
             
              class << self
         | 
| 52 52 | 
             
                attr_accessor :arguments, :named_arguments, :cli_args
         | 
| 53 | 
            +
             | 
| 53 54 | 
             
                ##
         | 
| 54 55 | 
             
                ## Holds a Configuration object with methods and a @settings hash
         | 
| 55 56 | 
             
                ##
         | 
| @@ -91,8 +92,6 @@ module Howzit | |
| 91 92 | 
             
                  @has_read_upstream ||= false
         | 
| 92 93 | 
             
                end
         | 
| 93 94 |  | 
| 94 | 
            -
                 | 
| 95 | 
            -
                  @has_read_upstream = has_read
         | 
| 96 | 
            -
                end
         | 
| 95 | 
            +
                attr_writer :has_read_upstream
         | 
| 97 96 | 
             
              end
         | 
| 98 97 | 
             
            end
         | 
    
        data/spec/topic_spec.rb
    CHANGED
    
    | @@ -9,7 +9,7 @@ describe Howzit::Topic do | |
| 9 9 |  | 
| 10 10 | 
             
              describe '.new' do
         | 
| 11 11 | 
             
                it 'makes a new topic instance' do
         | 
| 12 | 
            -
                  expect(topic).to be_a  | 
| 12 | 
            +
                  expect(topic).to be_a described_class
         | 
| 13 13 | 
             
                end
         | 
| 14 14 | 
             
                it 'has the correct title' do
         | 
| 15 15 | 
             
                  expect(topic.title).to eq title
         | 
| @@ -51,9 +51,11 @@ describe Howzit::Topic do | |
| 51 51 | 
             
                it 'returns true for matching pattern in content' do
         | 
| 52 52 | 
             
                  expect(topic.grep('prereq.*?ite')).to be_truthy
         | 
| 53 53 | 
             
                end
         | 
| 54 | 
            +
             | 
| 54 55 | 
             
                it 'returns true for matching pattern in title' do
         | 
| 55 56 | 
             
                  expect(topic.grep('bal.*?na')).to be_truthy
         | 
| 56 57 | 
             
                end
         | 
| 58 | 
            +
             | 
| 57 59 | 
             
                it 'fails on bad pattern' do
         | 
| 58 60 | 
             
                  expect(topic.grep('xxx+')).to_not be_truthy
         | 
| 59 61 | 
             
                end
         | 
| @@ -61,10 +63,12 @@ describe Howzit::Topic do | |
| 61 63 |  | 
| 62 64 | 
             
              describe '.run' do
         | 
| 63 65 | 
             
                Howzit.options[:default] = true
         | 
| 66 | 
            +
             | 
| 64 67 | 
             
                it 'shows prereq and postreq' do
         | 
| 65 68 | 
             
                  expect { topic.run }.to output(/prerequisite/).to_stdout
         | 
| 66 69 | 
             
                  expect { topic.run }.to output(/postrequisite/).to_stdout
         | 
| 67 70 | 
             
                end
         | 
| 71 | 
            +
             | 
| 68 72 | 
             
                it 'Copies to clipboard' do
         | 
| 69 73 | 
             
                  expect {
         | 
| 70 74 | 
             
                    ENV['RUBYOPT'] = '-W1'
         | 
| @@ -77,15 +81,18 @@ describe Howzit::Topic do | |
| 77 81 | 
             
              describe '.print_out' do
         | 
| 78 82 | 
             
                Howzit.options[:header_format] = :block
         | 
| 79 83 | 
             
                Howzit.options[:color] = false
         | 
| 84 | 
            +
             | 
| 80 85 | 
             
                it 'prints the topic title' do
         | 
| 81 | 
            -
                  expect(topic.print_out({single: true, header: true}).join("\n").uncolor).to match(/▌Topic Balogna/)
         | 
| 86 | 
            +
                  expect(topic.print_out({ single: true, header: true }).join("\n").uncolor).to match(/▌Topic Balogna/)
         | 
| 82 87 | 
             
                end
         | 
| 88 | 
            +
             | 
| 83 89 | 
             
                it 'prints a task title' do
         | 
| 84 | 
            -
                  expect(topic.print_out({single: true, header: true}).join("\n").uncolor).to match(/▶ Null Output/)
         | 
| 90 | 
            +
                  expect(topic.print_out({ single: true, header: true }).join("\n").uncolor).to match(/▶ Null Output/)
         | 
| 85 91 | 
             
                end
         | 
| 92 | 
            +
             | 
| 86 93 | 
             
                it 'prints task action with --show-code' do
         | 
| 87 94 | 
             
                  Howzit.options[:show_all_code] = true
         | 
| 88 | 
            -
                  expect(topic.print_out({single: true, header: true}).join("\n").uncolor).to match(/▶ ls -1/)
         | 
| 95 | 
            +
                  expect(topic.print_out({ single: true, header: true }).join("\n").uncolor).to match(/▶ ls -1/)
         | 
| 89 96 | 
             
                end
         | 
| 90 97 | 
             
              end
         | 
| 91 98 | 
             
            end
         | 
    
        data/src/_README.md
    ADDED
    
    | @@ -0,0 +1,145 @@ | |
| 1 | 
            +
            <!--README--><!--GITHUB-->
         | 
| 2 | 
            +
            # Howzit
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            [](https://rubygems.org/gems/howzit)
         | 
| 5 | 
            +
            [](https://travis-ci.org/makenew/ruby-gem)
         | 
| 6 | 
            +
            [](./LICENSE.txt)
         | 
| 7 | 
            +
            <!--END GITHUB-->
         | 
| 8 | 
            +
            A command-line reference tool for tracking project build systems
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            Howzit is a tool that allows you to keep Markdown-formatted notes about a project's tools and procedures. It functions as an easy lookup for notes about a particular task, as well as a task runner to automatically execute appropriate commands.
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            ## Features
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            - Match topic titles with any portion of title
         | 
| 15 | 
            +
            - Automatic pagination of output, with optional Markdown highlighting
         | 
| 16 | 
            +
            - Use `@run()`, `@copy()`, and `@open()` to perform actions within a build notes file
         | 
| 17 | 
            +
            - Use `@include()` to import another topic's tasks
         | 
| 18 | 
            +
            - Use fenced code blocks to include/run embedded scripts
         | 
| 19 | 
            +
            - Sets iTerm 2 marks on topic titles for navigation when paging is disabled
         | 
| 20 | 
            +
            - Inside of git repositories, howzit will work from subdirectories, assuming build notes are in top level of repo
         | 
| 21 | 
            +
            - Templates for easily including repeat tasks
         | 
| 22 | 
            +
            - Grep topics for pattern and choose from matches
         | 
| 23 | 
            +
            - Use positional and named variables when executing tasks
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            ## Getting Started
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            ### Prerequisites
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            - Ruby 2.4+ (It probably works on older Rubys, but is untested prior to 2.4.1.)
         | 
| 30 | 
            +
            - Optional: if [`fzf`](https://github.com/junegunn/fzf) is available, it will be used for handling multiple choice selections
         | 
| 31 | 
            +
            - Optional: if [`bat`](https://github.com/sharkdp/bat) is available it will page with that
         | 
| 32 | 
            +
            - Optional: [`mdless`](https://github.com/ttscoff/mdless) or [`mdcat`](https://github.com/lunaryorn/mdcat) for formatting output
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            ### Installing
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            You can install `howzit` by running:
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                gem install howzit
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            If you run into permission errors using the above command, you'll need to use `gem install --user-install howzit`. If that fails, either use `sudo` (`sudo gem install howzit`) or if you're using Homebrew, you have the option to install via [brew-gem](https://github.com/sportngin/brew-gem):
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                brew install brew-gem
         | 
| 43 | 
            +
                brew gem install howzit
         | 
| 44 | 
            +
             | 
| 45 | 
            +
            ### Usage
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            [See the wiki](https://github.com/ttscoff/howzit/wiki) for documentation.
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            ## Author
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            **Brett Terpstra** - [brettterpstra.com](https://brettterpstra.com)
         | 
| 52 | 
            +
             | 
| 53 | 
            +
            ## License
         | 
| 54 | 
            +
             | 
| 55 | 
            +
            This project is licensed under the MIT License - see the [LICENSE.txt](LICENSE.txt) file for details.
         | 
| 56 | 
            +
             | 
| 57 | 
            +
            ## Warranty
         | 
| 58 | 
            +
             | 
| 59 | 
            +
            This software is provided "as is" and without any express or
         | 
| 60 | 
            +
            implied warranties, including, without limitation, the implied
         | 
| 61 | 
            +
            warranties of merchantibility and fitness for a particular
         | 
| 62 | 
            +
            purpose.
         | 
| 63 | 
            +
             | 
| 64 | 
            +
            ## Documentation
         | 
| 65 | 
            +
             | 
| 66 | 
            +
            - [Howzit Wiki][Wiki].
         | 
| 67 | 
            +
            - [YARD documentation][RubyDoc] is hosted by RubyDoc.info.
         | 
| 68 | 
            +
            - [Interactive documentation][Omniref] is hosted by Omniref.
         | 
| 69 | 
            +
             | 
| 70 | 
            +
            [Wiki]: https://github.com/ttscoff/howzit/wiki
         | 
| 71 | 
            +
            [RubyDoc]: http://www.rubydoc.info/gems/howzit
         | 
| 72 | 
            +
            [Omniref]: https://www.omniref.com/ruby/gems/howzit
         | 
| 73 | 
            +
             | 
| 74 | 
            +
            <!--GITHUB-->
         | 
| 75 | 
            +
            ## Development and Testing
         | 
| 76 | 
            +
             | 
| 77 | 
            +
            ### Source Code
         | 
| 78 | 
            +
             | 
| 79 | 
            +
            The [howzit source] is hosted on GitHub.
         | 
| 80 | 
            +
            Clone the project with
         | 
| 81 | 
            +
             | 
| 82 | 
            +
            ```
         | 
| 83 | 
            +
            $ git clone https://github.com/ttscoff/howzit.git
         | 
| 84 | 
            +
            ```
         | 
| 85 | 
            +
             | 
| 86 | 
            +
            [howzit source]: https://github.com/ttscoff/howzit
         | 
| 87 | 
            +
             | 
| 88 | 
            +
            ### Requirements
         | 
| 89 | 
            +
             | 
| 90 | 
            +
            You will need [Ruby] with [Bundler].
         | 
| 91 | 
            +
             | 
| 92 | 
            +
            Install the development dependencies with
         | 
| 93 | 
            +
             | 
| 94 | 
            +
            ```
         | 
| 95 | 
            +
            $ bundle
         | 
| 96 | 
            +
            ```
         | 
| 97 | 
            +
             | 
| 98 | 
            +
            [Bundler]: http://bundler.io/
         | 
| 99 | 
            +
            [Ruby]: https://www.ruby-lang.org/
         | 
| 100 | 
            +
             | 
| 101 | 
            +
            ### Rake
         | 
| 102 | 
            +
             | 
| 103 | 
            +
            Run `$ rake -T` to see all Rake tasks.
         | 
| 104 | 
            +
             | 
| 105 | 
            +
            ```
         | 
| 106 | 
            +
            rake build                 # Build howzit-2.0.1.gem into the pkg directory
         | 
| 107 | 
            +
            rake bump:current[tag]     # Show current gem version
         | 
| 108 | 
            +
            rake bump:major[tag]       # Bump major part of gem version
         | 
| 109 | 
            +
            rake bump:minor[tag]       # Bump minor part of gem version
         | 
| 110 | 
            +
            rake bump:patch[tag]       # Bump patch part of gem version
         | 
| 111 | 
            +
            rake bump:pre[tag]         # Bump pre part of gem version
         | 
| 112 | 
            +
            rake bump:set              # Sets the version number using the VERSION environment variable
         | 
| 113 | 
            +
            rake clean                 # Remove any temporary products
         | 
| 114 | 
            +
            rake clobber               # Remove any generated files
         | 
| 115 | 
            +
            rake install               # Build and install howzit-2.0.1.gem into system gems
         | 
| 116 | 
            +
            rake install:local         # Build and install howzit-2.0.1.gem into system gems without network access
         | 
| 117 | 
            +
            rake release[remote]       # Create tag v2.0.1 and build and push howzit-2.0.1.gem to Rubygems
         | 
| 118 | 
            +
            rake rubocop               # Run RuboCop
         | 
| 119 | 
            +
            rake rubocop:auto_correct  # Auto-correct RuboCop offenses
         | 
| 120 | 
            +
            rake spec                  # Run RSpec code examples
         | 
| 121 | 
            +
            rake test                  # Run test suite
         | 
| 122 | 
            +
            rake yard                  # Generate YARD Documentation
         | 
| 123 | 
            +
            ```
         | 
| 124 | 
            +
             | 
| 125 | 
            +
            ### Guard
         | 
| 126 | 
            +
             | 
| 127 | 
            +
            Guard tasks have been separated into the following groups:
         | 
| 128 | 
            +
            `doc`, `lint`, and `unit`.
         | 
| 129 | 
            +
            By default, `$ guard` will generate documentation, lint, and run unit tests.
         | 
| 130 | 
            +
             | 
| 131 | 
            +
            ## Contributing
         | 
| 132 | 
            +
             | 
| 133 | 
            +
            Please submit and comment on bug reports and feature requests.
         | 
| 134 | 
            +
             | 
| 135 | 
            +
            To submit a patch:
         | 
| 136 | 
            +
             | 
| 137 | 
            +
            1. Fork it (https://github.com/ttscoff/howzit/fork).
         | 
| 138 | 
            +
            2. Create your feature branch (`git checkout -b my-new-feature`).
         | 
| 139 | 
            +
            3. Make changes. Write and run tests.
         | 
| 140 | 
            +
            4. Commit your changes (`git commit -am 'Add some feature'`).
         | 
| 141 | 
            +
            5. Push to the branch (`git push origin my-new-feature`).
         | 
| 142 | 
            +
            6. Create a new Pull Request.
         | 
| 143 | 
            +
             | 
| 144 | 
            +
            <!--END GITHUB-->
         | 
| 145 | 
            +
            <!--END README-->
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: howzit
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 2.1. | 
| 4 | 
            +
              version: 2.1.13
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Brett Terpstra
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2024- | 
| 11 | 
            +
            date: 2024-08-05 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bundler
         | 
| @@ -339,6 +339,7 @@ files: | |
| 339 339 | 
             
            - spec/task_spec.rb
         | 
| 340 340 | 
             
            - spec/topic_spec.rb
         | 
| 341 341 | 
             
            - spec/util_spec.rb
         | 
| 342 | 
            +
            - src/_README.md
         | 
| 342 343 | 
             
            - update_readmes.rb
         | 
| 343 344 | 
             
            homepage: https://github.com/ttscoff/howzit
         | 
| 344 345 | 
             
            licenses:
         | 
| @@ -359,7 +360,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 359 360 | 
             
                - !ruby/object:Gem::Version
         | 
| 360 361 | 
             
                  version: '0'
         | 
| 361 362 | 
             
            requirements: []
         | 
| 362 | 
            -
            rubygems_version: 3.2. | 
| 363 | 
            +
            rubygems_version: 3.2.15
         | 
| 363 364 | 
             
            signing_key:
         | 
| 364 365 | 
             
            specification_version: 4
         | 
| 365 366 | 
             
            summary: Provides a way to access Markdown project notes by topic with query capabilities
         |