twig 1.2.1 → 1.3
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.
- data/HISTORY.md +14 -1
- data/README.md +11 -5
- data/bin/twig +2 -2
- data/bin/twig-gh-open +3 -2
- data/bin/twig-gh-open-issue +2 -1
- data/lib/twig.rb +13 -12
- data/lib/twig/cli.rb +77 -33
- data/lib/twig/display.rb +55 -33
- data/lib/twig/github.rb +10 -7
- data/lib/twig/options.rb +59 -7
- data/lib/twig/util.rb +4 -0
- data/lib/twig/version.rb +1 -1
- data/spec/twig/cli_spec.rb +106 -13
- data/spec/twig/display_spec.rb +131 -23
- data/spec/twig/github_spec.rb +299 -0
- data/spec/twig/options_spec.rb +108 -7
- data/spec/twig/util_spec.rb +24 -0
- data/spec/twig_spec.rb +41 -27
- data/twig.gemspec +4 -3
- metadata +26 -9
    
        data/HISTORY.md
    CHANGED
    
    | @@ -1,9 +1,22 @@ | |
| 1 1 | 
             
            Twig
         | 
| 2 2 | 
             
            ====
         | 
| 3 3 |  | 
| 4 | 
            +
            1.3 (2013-05-22)
         | 
| 5 | 
            +
            ----------------
         | 
| 6 | 
            +
            * ENHANCEMENT: Add `--branch-width` and `--<property>-width` options for setting
         | 
| 7 | 
            +
              custom column widths.
         | 
| 8 | 
            +
            * ENHANCEMENT: Add `--reverse` option for listing least recently updated
         | 
| 9 | 
            +
              branches first. This can be used in a config file as `reverse: true`.
         | 
| 10 | 
            +
            * ENHANCEMENT: Make `gh-open` and `gh-open-issue` work cross-platform.
         | 
| 11 | 
            +
              (GH-18. Thanks [ixti](https://github.com/ixti)!)
         | 
| 12 | 
            +
            * FIX: Allow getting, setting, and unsetting properties for branches older than
         | 
| 13 | 
            +
              the `max-days-old` option, if given.
         | 
| 14 | 
            +
            * FIX: Abort `twig gh-*` subcommands early if working in a non-Github
         | 
| 15 | 
            +
              repository.
         | 
| 16 | 
            +
             | 
| 4 17 | 
             
            1.2.1 (2013-05-04)
         | 
| 5 18 | 
             
            ------------------
         | 
| 6 | 
            -
            * FIX: Add User-Agent string to `twig | 
| 19 | 
            +
            * FIX: Add User-Agent string to `twig gh-update` GitHub requests to comply with
         | 
| 7 20 | 
             
              GitHub API v3.
         | 
| 8 21 |  | 
| 9 22 | 
             
            1.2 (2013-03-21)
         | 
    
        data/README.md
    CHANGED
    
    | @@ -43,13 +43,21 @@ chronologically with their properties. | |
| 43 43 | 
             
            * `twig <property> -b <branch>`:         Get property for any branch
         | 
| 44 44 | 
             
            * `twig <property> <value> -b <branch>`: Set property for any branch
         | 
| 45 45 | 
             
            * `twig --unset <property> -b <branch>`: Unset property for any branch
         | 
| 46 | 
            -
            * `twig --header-style <format>`:        Change the header style, e.g., "red", "green bold"
         | 
| 47 46 | 
             
            * `twig init-completion`:                Set up tab completion for `-b` and `--branch`
         | 
| 48 47 | 
             
            * `twig --help`:                         More info
         | 
| 49 48 |  | 
| 50 49 |  | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 50 | 
            +
            Display options
         | 
| 51 | 
            +
            ---------------
         | 
| 52 | 
            +
             | 
| 53 | 
            +
            * `twig --header-style <format>`:       Change the header style, e.g., "red", "green bold"
         | 
| 54 | 
            +
            * `twig --branch-width <number>`:       Set the character width for the `branch` column
         | 
| 55 | 
            +
            * `twig --<property>-width <number>`:   Set the character width for a specific property column
         | 
| 56 | 
            +
            * `twig --reverse`:                     List oldest branches first
         | 
| 57 | 
            +
             | 
| 58 | 
            +
             | 
| 59 | 
            +
            Filtering options
         | 
| 60 | 
            +
            -----------------
         | 
| 53 61 |  | 
| 54 62 | 
             
            Twig lists all of your branches by default (newest first), but you can filter
         | 
| 55 63 | 
             
            them by age, name, and custom properties:
         | 
| @@ -154,7 +162,6 @@ a browser window if possible: | |
| 154 162 |  | 
| 155 163 | 
             
                $ twig gh-open
         | 
| 156 164 | 
             
                GitHub URL: https://github.com/myname/myproject
         | 
| 157 | 
            -
                # Also opens a browser window (OS X only).
         | 
| 158 165 |  | 
| 159 166 | 
             
            If you're working on an issue for a GitHub repository, the `gh-update`
         | 
| 160 167 | 
             
            subcommand syncs issue statuses with GitHub:
         | 
| @@ -193,7 +200,6 @@ subcommand to view that issue on GitHub: | |
| 193 200 | 
             
                # Current branch:
         | 
| 194 201 | 
             
                $ twig gh-open-issue
         | 
| 195 202 | 
             
                GitHub issue URL: https://github.com/myname/myproject/issues/111
         | 
| 196 | 
            -
                # Also opens a browser window (OS X only).
         | 
| 197 203 |  | 
| 198 204 | 
             
                # Any branch:
         | 
| 199 205 | 
             
                $ twig gh-open-issue -b <branch name>
         | 
    
        data/bin/twig
    CHANGED
    
    | @@ -2,13 +2,13 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'twig'))
         | 
| 4 4 |  | 
| 5 | 
            -
            twig = Twig.new
         | 
| 6 5 | 
             
            repo_required = ARGV != ['--help'] && ARGV != ['help'] && ARGV != ['--version']
         | 
| 7 6 |  | 
| 8 | 
            -
            if repo_required && ! | 
| 7 | 
            +
            if repo_required && !Twig.repo?
         | 
| 9 8 | 
             
              abort "Current directory is not a git repository."
         | 
| 10 9 | 
             
            end
         | 
| 11 10 |  | 
| 12 11 | 
             
            # Gettin' twiggy wit' it.
         | 
| 12 | 
            +
            twig = Twig.new
         | 
| 13 13 | 
             
            twig.read_config_file!
         | 
| 14 14 | 
             
            twig.read_cli_args!(ARGV)
         | 
    
        data/bin/twig-gh-open
    CHANGED
    
    | @@ -5,10 +5,11 @@ | |
| 5 5 | 
             
            # Author: Ron DeVera <http://rondevera.com>
         | 
| 6 6 |  | 
| 7 7 | 
             
            require 'rubygems'
         | 
| 8 | 
            -
            require 'twig | 
| 8 | 
            +
            require 'twig'
         | 
| 9 | 
            +
            require 'launchy'
         | 
| 9 10 |  | 
| 10 11 | 
             
            Twig::GithubRepo.new do |gh_repo|
         | 
| 11 12 | 
             
              url = "https://github.com/#{gh_repo.username}/#{gh_repo.repository}"
         | 
| 12 13 | 
             
              puts "GitHub URL: #{url}"
         | 
| 13 | 
            -
               | 
| 14 | 
            +
              Launchy.open(url) rescue nil
         | 
| 14 15 | 
             
            end
         | 
    
        data/bin/twig-gh-open-issue
    CHANGED
    
    | @@ -10,6 +10,7 @@ | |
| 10 10 |  | 
| 11 11 | 
             
            require 'rubygems'
         | 
| 12 12 | 
             
            require 'twig'
         | 
| 13 | 
            +
            require 'launchy'
         | 
| 13 14 |  | 
| 14 15 | 
             
            Twig::GithubRepo.new do |gh_repo|
         | 
| 15 16 | 
             
              twig = Twig.new
         | 
| @@ -25,5 +26,5 @@ Twig::GithubRepo.new do |gh_repo| | |
| 25 26 | 
             
              url << "/issues/#{issue_id}"
         | 
| 26 27 |  | 
| 27 28 | 
             
              puts "GitHub issue URL: #{url}"
         | 
| 28 | 
            -
               | 
| 29 | 
            +
              Launchy.open(url) rescue nil
         | 
| 29 30 | 
             
            end
         | 
    
        data/lib/twig.rb
    CHANGED
    
    | @@ -18,6 +18,11 @@ class Twig | |
| 18 18 | 
             
                `#{command}`.strip
         | 
| 19 19 | 
             
              end
         | 
| 20 20 |  | 
| 21 | 
            +
              def self.repo?
         | 
| 22 | 
            +
                Twig.run('git rev-parse 2>&1')
         | 
| 23 | 
            +
                $?.success?
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
             | 
| 21 26 | 
             
              def initialize
         | 
| 22 27 | 
             
                self.options = {}
         | 
| 23 28 |  | 
| @@ -25,14 +30,8 @@ class Twig | |
| 25 30 | 
             
                set_option(:header_style, DEFAULT_HEADER_COLOR.to_s)
         | 
| 26 31 | 
             
              end
         | 
| 27 32 |  | 
| 28 | 
            -
              def repo?
         | 
| 29 | 
            -
                Twig.run('git rev-parse 2>&1')
         | 
| 30 | 
            -
                $?.success?
         | 
| 31 | 
            -
              end
         | 
| 32 | 
            -
             | 
| 33 33 | 
             
              def current_branch_name
         | 
| 34 | 
            -
                @_current_branch_name ||=
         | 
| 35 | 
            -
                  Twig.run('git symbolic-ref -q HEAD').sub(%r{^#{ REF_PREFIX }}, '')
         | 
| 34 | 
            +
                @_current_branch_name ||= Twig.run('git rev-parse --abbrev-ref HEAD')
         | 
| 36 35 | 
             
              end
         | 
| 37 36 |  | 
| 38 37 | 
             
              def all_branches
         | 
| @@ -84,8 +83,8 @@ class Twig | |
| 84 83 | 
             
                end
         | 
| 85 84 | 
             
              end
         | 
| 86 85 |  | 
| 87 | 
            -
              def  | 
| 88 | 
            -
                 | 
| 86 | 
            +
              def all_branch_names
         | 
| 87 | 
            +
                all_branches.map { |branch| branch.name }
         | 
| 89 88 | 
             
              end
         | 
| 90 89 |  | 
| 91 90 |  | 
| @@ -103,9 +102,11 @@ class Twig | |
| 103 102 |  | 
| 104 103 | 
             
                out = "\n" << branch_list_headers(options)
         | 
| 105 104 |  | 
| 106 | 
            -
                # List  | 
| 107 | 
            -
                listable_branches =
         | 
| 108 | 
            -
             | 
| 105 | 
            +
                # List least recently modified branches first
         | 
| 106 | 
            +
                listable_branches = branches.sort_by { |branch| branch.last_commit_time }
         | 
| 107 | 
            +
                if options[:reverse] != true
         | 
| 108 | 
            +
                  listable_branches.reverse! # List most recently modified branches first
         | 
| 109 | 
            +
                end
         | 
| 109 110 |  | 
| 110 111 | 
             
                branch_lines = listable_branches.inject([]) do |result, branch|
         | 
| 111 112 | 
             
                  result << branch_list_line(branch)
         | 
    
        data/lib/twig/cli.rb
    CHANGED
    
    | @@ -12,7 +12,7 @@ class Twig | |
| 12 12 | 
             
                    for your Git branches.
         | 
| 13 13 | 
             
                  })
         | 
| 14 14 |  | 
| 15 | 
            -
                  <<-BANNER.gsub(/^[ ]+/, '')
         | 
| 15 | 
            +
                  intro = <<-BANNER.gsub(/^[ ]+/, '')
         | 
| 16 16 |  | 
| 17 17 | 
             
                    #{version_string}
         | 
| 18 18 | 
             
                    #{'-' * version_string.size}
         | 
| @@ -20,8 +20,9 @@ class Twig | |
| 20 20 | 
             
                    #{intro}
         | 
| 21 21 |  | 
| 22 22 | 
             
                    #{Twig::HOMEPAGE}
         | 
| 23 | 
            -
             | 
| 24 23 | 
             
                  BANNER
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  intro + ' ' # Force extra blank line
         | 
| 25 26 | 
             
                end
         | 
| 26 27 |  | 
| 27 28 | 
             
                def help_separator(option_parser, text, options={})
         | 
| @@ -54,11 +55,47 @@ class Twig | |
| 54 55 | 
             
                  lines
         | 
| 55 56 | 
             
                end
         | 
| 56 57 |  | 
| 58 | 
            +
                def help_description_for_custom_property(option_parser, desc_lines)
         | 
| 59 | 
            +
                  indent = '      '
         | 
| 60 | 
            +
                  left_column_width = 29
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                  help_desc = desc_lines.inject('') do |desc, (left_column, right_column)|
         | 
| 63 | 
            +
                    desc + indent +
         | 
| 64 | 
            +
                    sprintf("%-#{left_column_width}s", left_column) + right_column + "\n"
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                  help_separator(option_parser, help_desc, :trailing => "\n")
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 57 70 | 
             
                def help_paragraph(text)
         | 
| 58 71 | 
             
                  help_description(text, :width => 80).join("\n")
         | 
| 59 72 | 
             
                end
         | 
| 60 73 |  | 
| 74 | 
            +
                def help_line_for_custom_property?(line)
         | 
| 75 | 
            +
                  is_custom_property_except = (
         | 
| 76 | 
            +
                    line.include?('--except-') &&
         | 
| 77 | 
            +
                    !line.include?('--except-branch') &&
         | 
| 78 | 
            +
                    !line.include?('--except-PROPERTY')
         | 
| 79 | 
            +
                  )
         | 
| 80 | 
            +
                  is_custom_property_only = (
         | 
| 81 | 
            +
                    line.include?('--only-') &&
         | 
| 82 | 
            +
                    !line.include?('--only-branch') &&
         | 
| 83 | 
            +
                    !line.include?('--only-PROPERTY')
         | 
| 84 | 
            +
                  )
         | 
| 85 | 
            +
                  is_custom_property_width = (
         | 
| 86 | 
            +
                    line =~ /--.+-width/ &&
         | 
| 87 | 
            +
                    !line.include?('--branch-width') &&
         | 
| 88 | 
            +
                    !line.include?('--PROPERTY-width')
         | 
| 89 | 
            +
                  )
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                  is_custom_property_except ||
         | 
| 92 | 
            +
                  is_custom_property_only ||
         | 
| 93 | 
            +
                  is_custom_property_width
         | 
| 94 | 
            +
                end
         | 
| 95 | 
            +
             | 
| 61 96 | 
             
                def read_cli_options!(args)
         | 
| 97 | 
            +
                  custom_properties = Twig::Branch.all_properties
         | 
| 98 | 
            +
             | 
| 62 99 | 
             
                  option_parser = OptionParser.new do |opts|
         | 
| 63 100 | 
             
                    opts.banner         = help_intro
         | 
| 64 101 | 
             
                    opts.summary_indent = ' ' * 2
         | 
| @@ -82,22 +119,17 @@ class Twig | |
| 82 119 |  | 
| 83 120 | 
             
                    desc = 'Show this help content.'
         | 
| 84 121 | 
             
                    opts.on('--help', *help_description(desc)) do
         | 
| 85 | 
            -
                      summary_lines = opts. | 
| 122 | 
            +
                      summary_lines = opts.to_s.split("\n")
         | 
| 86 123 |  | 
| 87 | 
            -
                      # Filter out  | 
| 124 | 
            +
                      # Filter out custom property lines
         | 
| 125 | 
            +
                      prev_line = nil
         | 
| 88 126 | 
             
                      summary_lines.each do |line|
         | 
| 89 | 
            -
                         | 
| 90 | 
            -
             | 
| 91 | 
            -
             | 
| 92 | 
            -
             | 
| 93 | 
            -
                        )
         | 
| 94 | 
            -
                        is_custom_property_except = (
         | 
| 95 | 
            -
                          line.include?('--except-') &&
         | 
| 96 | 
            -
                          !line.include?('--except-branch') &&
         | 
| 97 | 
            -
                          !line.include?('--except-PROPERTY')
         | 
| 98 | 
            -
                        )
         | 
| 99 | 
            -
                        unless is_custom_property_only || is_custom_property_except
         | 
| 127 | 
            +
                        # Squash successive blank lines
         | 
| 128 | 
            +
                        next if line == "\n" && prev_line == "\n"
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                        unless help_line_for_custom_property?(line)
         | 
| 100 131 | 
             
                          puts line
         | 
| 132 | 
            +
                          prev_line = line
         | 
| 101 133 | 
             
                        end
         | 
| 102 134 | 
             
                      end
         | 
| 103 135 |  | 
| @@ -129,16 +161,10 @@ class Twig | |
| 129 161 | 
             
                    end
         | 
| 130 162 |  | 
| 131 163 | 
             
                    desc = 'Do not list branches whose name matches a given pattern.'
         | 
| 132 | 
            -
                    opts.on(
         | 
| 133 | 
            -
                      '--except-branch PATTERN',
         | 
| 134 | 
            -
                      *help_description(desc, :add_separator => false)
         | 
| 135 | 
            -
                        # `:add_separator => false` skips the extra line generated by the
         | 
| 136 | 
            -
                        # custom property filters below.
         | 
| 137 | 
            -
                    ) do |pattern|
         | 
| 164 | 
            +
                    opts.on('--except-branch PATTERN', *help_description(desc)) do |pattern|
         | 
| 138 165 | 
             
                      set_option(:property_except, :branch => pattern)
         | 
| 139 166 | 
             
                    end
         | 
| 140 167 |  | 
| 141 | 
            -
                    custom_properties = Twig::Branch.all_properties
         | 
| 142 168 | 
             
                    custom_properties.each do |property_name|
         | 
| 143 169 | 
             
                      opts.on("--only-#{property_name} PATTERN") do |pattern|
         | 
| 144 170 | 
             
                        set_option(:property_only, property_name.to_sym => pattern)
         | 
| @@ -148,18 +174,14 @@ class Twig | |
| 148 174 | 
             
                        set_option(:property_except, property_name.to_sym => pattern)
         | 
| 149 175 | 
             
                      end
         | 
| 150 176 | 
             
                    end
         | 
| 151 | 
            -
             | 
| 152 | 
            -
                    custom_properties_desc_lines = [
         | 
| 177 | 
            +
                    help_description_for_custom_property(opts, [
         | 
| 153 178 | 
             
                      ['--only-PROPERTY PATTERN',   'Only list branches with a given property'],
         | 
| 154 179 | 
             
                      ['',                          'that matches a given pattern.'],
         | 
| 155 | 
            -
             | 
| 180 | 
            +
                    ])
         | 
| 181 | 
            +
                    help_description_for_custom_property(opts, [
         | 
| 156 182 | 
             
                      ['--except-PROPERTY PATTERN', 'Do not list branches with a given property'],
         | 
| 157 183 | 
             
                      ['',                          'that matches a given pattern.']
         | 
| 158 | 
            -
                    ]
         | 
| 159 | 
            -
                    custom_properties_desc = custom_properties_desc_lines.inject('') do |desc, line_parts|
         | 
| 160 | 
            -
                      desc + sprintf('      %-29s', line_parts[0]) + line_parts[1] + "\n"
         | 
| 161 | 
            -
                    end
         | 
| 162 | 
            -
                    help_separator(opts, custom_properties_desc, :trailing => "\n")
         | 
| 184 | 
            +
                    ])
         | 
| 163 185 |  | 
| 164 186 | 
             
                    desc =
         | 
| 165 187 | 
             
                      'Lists all branches regardless of other filtering options. ' +
         | 
| @@ -175,11 +197,25 @@ class Twig | |
| 175 197 |  | 
| 176 198 | 
             
                    help_separator(opts, 'Listing branches:')
         | 
| 177 199 |  | 
| 200 | 
            +
                    desc = 'Set the width for the `branch` column.'
         | 
| 201 | 
            +
                    opts.on('--branch-width NUMBER', *help_description(desc)) do |width|
         | 
| 202 | 
            +
                      set_option(:property_width, :branch => width)
         | 
| 203 | 
            +
                    end
         | 
| 204 | 
            +
             | 
| 205 | 
            +
                    custom_properties.each do |property_name|
         | 
| 206 | 
            +
                      opts.on("--#{property_name}-width NUMBER") do |width|
         | 
| 207 | 
            +
                        set_option(:property_width, property_name.to_sym => width)
         | 
| 208 | 
            +
                      end
         | 
| 209 | 
            +
                    end
         | 
| 210 | 
            +
                    help_description_for_custom_property(opts, [
         | 
| 211 | 
            +
                      ['--PROPERTY-width NUMBER', "Set the width for a given property's column."]
         | 
| 212 | 
            +
                    ])
         | 
| 213 | 
            +
             | 
| 178 214 | 
             
                    colors = Twig::Display::COLORS.keys.map do |value|
         | 
| 179 | 
            -
                      format_string(value,  | 
| 215 | 
            +
                      format_string(value, :color => value)
         | 
| 180 216 | 
             
                    end.join(', ')
         | 
| 181 217 | 
             
                    weights = Twig::Display::WEIGHTS.keys.map do |value|
         | 
| 182 | 
            -
                      format_string(value,  | 
| 218 | 
            +
                      format_string(value, :weight => value)
         | 
| 183 219 | 
             
                    end.join(' and ')
         | 
| 184 220 | 
             
                    default_color = format_string(
         | 
| 185 221 | 
             
                      Twig::DEFAULT_HEADER_COLOR.to_s,
         | 
| @@ -190,10 +226,18 @@ class Twig | |
| 190 226 | 
             
                      Valid colors are #{colors}. Valid weights are #{weights}.
         | 
| 191 227 | 
             
                      The default is "#{default_color}".
         | 
| 192 228 | 
             
                    DESC
         | 
| 193 | 
            -
                    opts.on( | 
| 229 | 
            +
                    opts.on(
         | 
| 230 | 
            +
                      '--header-style "STYLE"',
         | 
| 231 | 
            +
                      *help_description(desc, :add_separator => true)
         | 
| 232 | 
            +
                    ) do |style|
         | 
| 194 233 | 
             
                      set_option(:header_style, style)
         | 
| 195 234 | 
             
                    end
         | 
| 196 235 |  | 
| 236 | 
            +
                    desc = 'Show oldest branches first.'
         | 
| 237 | 
            +
                    opts.on('--reverse', *help_description(desc)) do
         | 
| 238 | 
            +
                      set_option(:reverse, true)
         | 
| 239 | 
            +
                    end
         | 
| 240 | 
            +
             | 
| 197 241 |  | 
| 198 242 |  | 
| 199 243 | 
             
                    help_separator(opts, help_paragraph(%{
         | 
    
        data/lib/twig/display.rb
    CHANGED
    
    | @@ -14,41 +14,58 @@ class Twig | |
| 14 14 | 
             
                  :normal => 0,
         | 
| 15 15 | 
             
                  :bold   => 1
         | 
| 16 16 | 
             
                }
         | 
| 17 | 
            +
                DEFAULT_PROPERTY_COLUMN_WIDTH = 16
         | 
| 18 | 
            +
                DEFAULT_BRANCH_COLUMN_WIDTH   = 48
         | 
| 17 19 | 
             
                CURRENT_BRANCH_INDICATOR        = '* '
         | 
| 18 20 | 
             
                EMPTY_BRANCH_PROPERTY_INDICATOR = '-'
         | 
| 19 21 |  | 
| 20 | 
            -
                def column(string | 
| 22 | 
            +
                def column(string, options = {})
         | 
| 21 23 | 
             
                  # Returns `string` with an exact fixed width. If `string` is too wide, it
         | 
| 22 24 | 
             
                  # is truncated with an ellipsis and a trailing space to separate columns.
         | 
| 23 25 | 
             
                  #
         | 
| 24 | 
            -
                  # ` | 
| 26 | 
            +
                  # `options`:
         | 
| 25 27 | 
             
                  # - `:color`:  `nil` by default. Accepts a key from `COLORS`.
         | 
| 26 28 | 
             
                  # - `:weight`: `nil` by default. Accepts a key from `WEIGHTS`.
         | 
| 27 29 | 
             
                  # - `:width`:  8 (characters) by default.
         | 
| 28 30 |  | 
| 29 | 
            -
                   | 
| 30 | 
            -
                   | 
| 31 | 
            -
                  new_string | 
| 32 | 
            -
                  omission | 
| 31 | 
            +
                  string ||= ' '
         | 
| 32 | 
            +
                  width      = options[:width] || 8
         | 
| 33 | 
            +
                  new_string = string[0, width]
         | 
| 34 | 
            +
                  omission   = '...'
         | 
| 33 35 |  | 
| 34 | 
            -
                  if string.size  | 
| 36 | 
            +
                  if string.size > width
         | 
| 35 37 | 
             
                    new_string[-omission.size, omission.size] = omission
         | 
| 36 38 | 
             
                  else
         | 
| 37 | 
            -
                    new_string = ' ' *  | 
| 39 | 
            +
                    new_string = ' ' * width
         | 
| 38 40 | 
             
                    new_string[0, string.size] = string
         | 
| 39 41 | 
             
                  end
         | 
| 40 42 |  | 
| 41 43 | 
             
                  new_string = format_string(
         | 
| 42 44 | 
             
                    new_string,
         | 
| 43 | 
            -
                     | 
| 45 | 
            +
                    options.reject { |k, v| ![:color, :weight].include?(k) }
         | 
| 44 46 | 
             
                  )
         | 
| 45 47 |  | 
| 46 48 | 
             
                  new_string
         | 
| 47 49 | 
             
                end
         | 
| 48 50 |  | 
| 51 | 
            +
                def date_time_column_width; 35; end
         | 
| 52 | 
            +
                def column_gutter; '  '; end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                def property_column_width(property_name = nil)
         | 
| 55 | 
            +
                  if property_name && options[:property_width]
         | 
| 56 | 
            +
                    width = options[:property_width][property_name.to_sym]
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  if width
         | 
| 60 | 
            +
                    width
         | 
| 61 | 
            +
                  elsif property_name == :branch
         | 
| 62 | 
            +
                    Twig::Display::DEFAULT_BRANCH_COLUMN_WIDTH
         | 
| 63 | 
            +
                  else
         | 
| 64 | 
            +
                    Twig::Display::DEFAULT_PROPERTY_COLUMN_WIDTH
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
             | 
| 49 68 | 
             
                def branch_list_headers(header_options = {})
         | 
| 50 | 
            -
                  columns_for_date_time    = 5
         | 
| 51 | 
            -
                  columns_per_property     = 2
         | 
| 52 69 | 
             
                  branch_indicator_padding = ' ' * CURRENT_BRANCH_INDICATOR.size
         | 
| 53 70 |  | 
| 54 71 | 
             
                  header_options.merge!(
         | 
| @@ -62,22 +79,22 @@ class Twig | |
| 62 79 | 
             
                    end
         | 
| 63 80 | 
             
                  )
         | 
| 64 81 |  | 
| 65 | 
            -
                  out =
         | 
| 66 | 
            -
             | 
| 67 | 
            -
                     | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 72 | 
            -
             | 
| 73 | 
            -
                  out <<
         | 
| 74 | 
            -
             | 
| 75 | 
            -
                     | 
| 76 | 
            -
             | 
| 77 | 
            -
                     | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 80 | 
            -
             | 
| 82 | 
            +
                  out = column(' ', :width => date_time_column_width) << column_gutter
         | 
| 83 | 
            +
                  out << Twig::Branch.all_properties.map do |property|
         | 
| 84 | 
            +
                    width = property_column_width(property)
         | 
| 85 | 
            +
                    column(property, header_options.merge(:width => width)) << column_gutter
         | 
| 86 | 
            +
                  end.join
         | 
| 87 | 
            +
                  out << column(branch_indicator_padding + 'branch', header_options)
         | 
| 88 | 
            +
                  out << "\n"
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                  out << column(' ', :width => date_time_column_width) << column_gutter
         | 
| 91 | 
            +
                  out << Twig::Branch.all_properties.map do |property|
         | 
| 92 | 
            +
                    width = property_column_width(property)
         | 
| 93 | 
            +
                    underline = '-' * property.size
         | 
| 94 | 
            +
                    column(underline, header_options.merge(:width => width)) << column_gutter
         | 
| 95 | 
            +
                  end.join
         | 
| 96 | 
            +
                  out << column(branch_indicator_padding + '------', header_options)
         | 
| 97 | 
            +
                  out << "\n"
         | 
| 81 98 |  | 
| 82 99 | 
             
                  out
         | 
| 83 100 | 
             
                end
         | 
| @@ -87,24 +104,29 @@ class Twig | |
| 87 104 |  | 
| 88 105 | 
             
                  properties = Twig::Branch.all_properties.inject({}) do |result, property_name|
         | 
| 89 106 | 
             
                    property = (get_branch_property(branch.name, property_name) || '').strip
         | 
| 90 | 
            -
                    property =  | 
| 107 | 
            +
                    property = EMPTY_BRANCH_PROPERTY_INDICATOR if property.empty?
         | 
| 91 108 | 
             
                    property.gsub!(/[\n\r]+/, ' ')
         | 
| 92 109 | 
             
                    result.merge(property_name => property)
         | 
| 93 110 | 
             
                  end
         | 
| 94 111 |  | 
| 95 | 
            -
                  line = column(branch.last_commit_time.to_s,  | 
| 112 | 
            +
                  line = column(branch.last_commit_time.to_s, :width => date_time_column_width)
         | 
| 113 | 
            +
                  line << column_gutter
         | 
| 96 114 |  | 
| 97 115 | 
             
                  line <<
         | 
| 98 116 | 
             
                    Twig::Branch.all_properties.map do |property_name|
         | 
| 99 | 
            -
                       | 
| 100 | 
            -
                       | 
| 117 | 
            +
                      property_value = properties[property_name] || ''
         | 
| 118 | 
            +
                      width = property_column_width(property_name)
         | 
| 119 | 
            +
                      column(property_value, :width => width) << column_gutter
         | 
| 101 120 | 
             
                    end.join
         | 
| 102 121 |  | 
| 122 | 
            +
                  branch_column_width = property_column_width(:branch)
         | 
| 123 | 
            +
                  branch_column = column(branch.to_s, :width => branch_column_width)
         | 
| 124 | 
            +
                  branch_column.strip! # Strip final column
         | 
| 103 125 | 
             
                  line <<
         | 
| 104 126 | 
             
                    if is_current_branch
         | 
| 105 | 
            -
                      CURRENT_BRANCH_INDICATOR +  | 
| 127 | 
            +
                      CURRENT_BRANCH_INDICATOR + branch_column
         | 
| 106 128 | 
             
                    else
         | 
| 107 | 
            -
                      (' ' * CURRENT_BRANCH_INDICATOR.size) +  | 
| 129 | 
            +
                      (' ' * CURRENT_BRANCH_INDICATOR.size) + branch_column
         | 
| 108 130 | 
             
                    end
         | 
| 109 131 |  | 
| 110 132 | 
             
                  line = format_string(line, :weight => :bold) if is_current_branch
         |