~ubuntu-branches/ubuntu/oneiric/ctioga2/oneiric

« back to all changes in this revision

Viewing changes to lib/ctioga2/commands/doc/help.rb

  • Committer: Bazaar Package Importer
  • Author(s): Vincent Fourmond
  • Date: 2011-01-24 21:36:06 UTC
  • Revision ID: james.westby@ubuntu.com-20110124213606-9ettx0ugl83z0bzp
Tags: upstream-0.1
ImportĀ upstreamĀ versionĀ 0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# help.rb: displaying the documentation of commands
 
2
# copyright (c) 2009 by Vincent Fourmond
 
3
  
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
  
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details (in the COPYING file).
 
13
 
 
14
require 'ctioga2/utils'
 
15
require 'ctioga2/commands/commands'
 
16
require 'ctioga2/commands/parsers/command-line'
 
17
require 'ctioga2/commands/doc/wordwrap'
 
18
 
 
19
module CTioga2
 
20
 
 
21
  Version::register_svn_info('$Revision: 132 $', '$Date: 2010-01-14 23:18:19 +0100 (Thu, 14 Jan 2010) $')
 
22
 
 
23
  module Commands
 
24
 
 
25
    module Documentation
 
26
 
 
27
      # Displays help about command-line options and such.
 
28
      class CommandLineHelp
 
29
 
 
30
        # How much space to leave for the options ?
 
31
        attr_accessor :options_column_width
 
32
 
 
33
        # How many columns do we have at all ?
 
34
        attr_accessor :total_width
 
35
 
 
36
        # Whether output has (moderate) terminal capabilities
 
37
        attr_accessor :to_tty
 
38
 
 
39
        # Whether we should send output to pager if output has
 
40
        # terminal support.
 
41
        attr_accessor :to_pager
 
42
 
 
43
        # Styles, ie a hash 'object' (option, argument...) => ANSI
 
44
        # color code.
 
45
        attr_accessor :styles
 
46
 
 
47
        # Color output ?
 
48
        attr_accessor :color
 
49
 
 
50
        # The default value for the #styles attribute.
 
51
        DefaultStyles = {
 
52
          'switch' => "01",
 
53
          'title' => "01;04",
 
54
          'arguments' => '32',
 
55
          'options' => '34'
 
56
        }
 
57
 
 
58
        # Creates an object to display command-line help. Available
 
59
        # values for the options are given by the hash
 
60
        # CommandLineHelpOptions. Their meaning is:
 
61
        # 
 
62
        # * 'pager': disables or enables the use of a pager when
 
63
        #   sending output to a terminal
 
64
        def initialize(options)
 
65
          @options_column_width = 20
 
66
          @to_pager = if options.key? 'pager'
 
67
                        options['pager']
 
68
                      else
 
69
                        true
 
70
                      end
 
71
 
 
72
          @styles = DefaultStyles.dup
 
73
          @color = true
 
74
        end
 
75
 
 
76
        # Prints short help text suitable for a --help option about
 
77
        # available commands, by groups (ungrouped last). It takes a
 
78
        # list of all commands (_cmds_) and the list of _groups_ to
 
79
        # display.
 
80
        # 
 
81
        # \todo maybe the part about sending to the pager should be
 
82
        # factorized into a neat utility class ?
 
83
        def print_commandline_options(cmds, groups)
 
84
          @to_tty = false
 
85
          if STDOUT.tty? 
 
86
            begin
 
87
              require 'curses'
 
88
              Curses.init_screen
 
89
              @total_width = Curses.cols
 
90
              Curses.close_screen
 
91
              @to_tty = true
 
92
            rescue
 
93
            end
 
94
          end
 
95
          @total_width ||= 80   # 80 by default
 
96
 
 
97
          # Disable color output if not a to a terminal
 
98
          if ! @to_tty
 
99
            @color = false
 
100
          end
 
101
 
 
102
          if @to_tty and @to_pager
 
103
            # We pass -R as default value...
 
104
            ENV['LESS'] = 'R'
 
105
            output = IO::popen("pager", "w")
 
106
            pager = true
 
107
          else
 
108
            output = $stdout
 
109
            pager = false
 
110
          end
 
111
          
 
112
          for group in groups
 
113
            output.puts unless group == groups[0]
 
114
            name = (group && group.name) || "Ungrouped commands"
 
115
            if group && group.blacklisted 
 
116
              name << " (blacklisted)"
 
117
            end
 
118
            output.puts style(name, 'title')
 
119
            for cmd in cmds[group].sort {|a,b|
 
120
                a.long_option <=> b.long_option
 
121
              }
 
122
 
 
123
              output.puts format_one_entry(cmd)
 
124
            end
 
125
          end
 
126
          output.close
 
127
        end
 
128
 
 
129
        protected
 
130
 
 
131
        # Formats one entry of the commands
 
132
        def format_one_entry(cmd)
 
133
          sh, long, desc = cmd.option_strings
 
134
          
 
135
          str = "#{leading_spaces}%2s%1s %-#{@options_column_width}s" % 
 
136
            [ sh, (sh ? "," : " "), long]
 
137
 
 
138
          size = @total_width - total_leading_spaces.size
 
139
 
 
140
          # Do the coloring: we need to parse option string first
 
141
          if str =~ /(.*--\S+)(.*)/
 
142
            switch = $1
 
143
            args = $2
 
144
            str = "#{style(switch,'switch')}#{style(args,'arguments')}"
 
145
          end
 
146
          
 
147
          # Now, add the description.
 
148
          desc_lines = WordWrapper.wrap(desc, size)
 
149
          if long.size >= @options_column_width
 
150
            str += "\n#{total_leading_spaces}"
 
151
          end
 
152
          str += desc_lines.join("\n#{total_leading_spaces}")
 
153
 
 
154
          if cmd.has_options?
 
155
            op_start = '  options: '
 
156
            options = cmd.optional_arguments.
 
157
              keys.sort.map { |x| "/#{x}"}.join(' ') 
 
158
            opts_lines = WordWrapper.wrap(options, size - op_start.size)
 
159
            str += "\n#{total_leading_spaces}#{style(op_start,'switch')}" + 
 
160
              style(opts_lines.join("\n#{total_leading_spaces}#{' ' * op_start.size}"), 'options')
 
161
          end
 
162
          return str
 
163
        end
 
164
 
 
165
        # Leading spaces to align a string with the other option texts
 
166
        def total_leading_spaces
 
167
          return "#{leading_spaces}#{" " *(@options_column_width + 4)}"
 
168
          # 4: '-o, '
 
169
        end
 
170
 
 
171
        # Spaces before any 'short' option appears
 
172
        def leading_spaces
 
173
          return "    "
 
174
        end
 
175
 
 
176
        # Colorizes some text with the given ANSI code.
 
177
        #
 
178
        # Word wrapping should be used *before*, as it will not work
 
179
        # after.
 
180
        def colorize(str, code)
 
181
          # We split into lines, as I'm unsure color status is kept
 
182
          # across lines
 
183
          return str.split("\n").map {|s|
 
184
            "\e[#{code}m#{s}\e[0m"
 
185
          }.join("\n")
 
186
        end
 
187
 
 
188
        # Changes the style of the object.
 
189
        def style(str, what)
 
190
          if ! @color
 
191
            return str
 
192
          end
 
193
          if @styles[what]
 
194
            return colorize(str, @styles[what])
 
195
          else
 
196
            return str
 
197
          end
 
198
        end
 
199
 
 
200
      end
 
201
 
 
202
    end
 
203
 
 
204
  end
 
205
 
 
206
end