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

« back to all changes in this revision

Viewing changes to lib/ctioga2/commands/doc/man.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
# man.rb: conversion of the internal help into a hand-modifiable manual page.
 
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/log'
 
16
require 'ctioga2/commands/commands'
 
17
require 'ctioga2/commands/parsers/command-line'
 
18
 
 
19
module CTioga2
 
20
 
 
21
  Version::register_svn_info('$Revision: 213 $', '$Date: 2010-12-31 02:50:00 +0100 (Fri, 31 Dec 2010) $')
 
22
 
 
23
  module Commands
 
24
 
 
25
    module Documentation
 
26
 
 
27
      # Converts help texts found in the Command descriptions into a
 
28
      # manual page that can be further edited and *updated* using this
 
29
      # module.
 
30
      class Man
 
31
 
 
32
        include Log
 
33
 
 
34
        # The Doc object Help2Man should be working on.
 
35
        attr_accessor :doc
 
36
 
 
37
        def initialize(doc)
 
38
          @doc = doc
 
39
        end
 
40
 
 
41
        RoffCommentRE = /\.\s*\\"/
 
42
 
 
43
        # Writes a manual page to the given _io_ stream, using _version_
 
44
        # as the target version (the one ending up in the headers).
 
45
        #
 
46
        # NO... We should *input* a manual page, and spit out
 
47
        # replacement texts.
 
48
        #
 
49
        def write_manual_page(version, input, out = STDOUT)
 
50
          passed_header = false
 
51
          if input.is_a? String
 
52
            filename = input
 
53
            input = File::open(input)
 
54
          elsif input.respond_to? :path
 
55
            filename = input.path
 
56
          else
 
57
            filename = "unkown"
 
58
          end
 
59
 
 
60
          @cmds, @groups = @doc.documented_commands
 
61
          @cmd_exclude = {}
 
62
          @group_exclude = {}
 
63
 
 
64
          while line = input.gets
 
65
            case line
 
66
            when /^#{RoffCommentRE}\s*write-header\s*$/
 
67
              out.puts header_string(version, filename)
 
68
              passed_header = true
 
69
            when /^#{RoffCommentRE}\s*write-commands\s*$/
 
70
              write_commands(out)
 
71
              # \todo add a write-backends command....
 
72
            when /^#{RoffCommentRE}\s*write-group:\s*(.*)\s*$/
 
73
              id = $1
 
74
              if @groups[id]
 
75
                write_group(out, g)
 
76
              else
 
77
                warn { "Unkown group: #{id}" }
 
78
              end
 
79
            when /^#{RoffCommentRE}\s*write-types\s*$/
 
80
              write_types(out)
 
81
            else
 
82
              if passed_header
 
83
                out.puts line
 
84
              end
 
85
            end
 
86
          end
 
87
          out.close
 
88
          input.close
 
89
        end
 
90
 
 
91
        protected
 
92
 
 
93
        ItemizeLabel = '\fB*\fR'
 
94
        ItemizeLabelSize = 2 
 
95
        ItemizeIndent = 2
 
96
        ManIndent = 8
 
97
 
 
98
        # Takes up an array of MarkupItem objects and returns its
 
99
        # equivalent in roff format. Alternativelely, it can take a
 
100
        # String and feed it to MarkedUpText.
 
101
        #
 
102
        # \todo make sure things are escaped the way they should be.
 
103
        #
 
104
        # if _inside_cmds_ is true, additional indentation is added
 
105
        # for the lists, so that is looks neat in the end.
 
106
        #
 
107
        # \todo try to be more clever about spaces in the target
 
108
        # file. (does not matter too much for the output of man)
 
109
        def markup_to_man(items, inside_cmds = true)
 
110
          if items.is_a? String 
 
111
            mup = MarkedUpText.new(@doc, items)
 
112
            return markup_to_man(mup.elements, inside_cmds)
 
113
          end
 
114
          str = ""
 
115
          for it in items
 
116
            case it
 
117
            when MarkedUpText::MarkupText
 
118
              str << it.to_s
 
119
            when MarkedUpText::MarkupLink
 
120
              str << "\\fI#{it.to_s}\\fR"
 
121
            when MarkedUpText::MarkupItemize
 
122
              indent = ItemizeIndent
 
123
              if inside_cmds
 
124
                indent += ManIndent
 
125
              end
 
126
              str << "\n.RS #{indent}"
 
127
              str << "\n.IP \"#{ItemizeLabel}\" #{ItemizeLabelSize}\n"
 
128
              str << it.items.map {
 
129
                |x| markup_to_man(x)
 
130
              }.join("\n.IP \"#{ItemizeLabel}\" #{ItemizeLabelSize}\n")
 
131
              str << "\n.RE\n\n"
 
132
              # We restore the indentation afterwards.
 
133
              if inside_cmds
 
134
                str << ".IP \"\" #{ManIndent}\n"
 
135
              end
 
136
            when MarkedUpText::MarkupVerbatim
 
137
              str << it.text.gsub(/^/, '  ')
 
138
            when MarkedUpText::MarkupParagraph
 
139
              str << "#{markup_to_man(it.elements)}\n\n"
 
140
            else
 
141
              raise "Markup #{it.class} isn't implemented yet for man"
 
142
            end
 
143
          end
 
144
          return str
 
145
        end
 
146
 
 
147
        # Writes out all commands to _out_.
 
148
        def write_commands(out)
 
149
          for group in @groups
 
150
            next if @group_exclude[group]
 
151
            write_group(out, group)
 
152
          end
 
153
        end
 
154
 
 
155
        # Writes out a single _group_ 
 
156
        def write_group(out, group)
 
157
          write_group_name(out, group)
 
158
          write_group_description(out, group)
 
159
          write_group_commands(out, group)
 
160
        end
 
161
 
 
162
        # Writes the name of a _group_ 
 
163
        def write_group_name(out, group)
 
164
          out.puts 
 
165
          out.puts ".SS #{group.name}"
 
166
          out.puts 
 
167
        end
 
168
 
 
169
        # Writes the description of a _group_.
 
170
        def write_group_description(out, group)
 
171
          out.puts 
 
172
          out.puts markup_to_man(group.description, false)
 
173
          out.puts 
 
174
        end
 
175
 
 
176
        # Writes the remaining commands of a group
 
177
        def write_group_commands(out, group)
 
178
          for cmd in @cmds[group].sort {|a,b|
 
179
              a.long_option <=> b.long_option
 
180
            }
 
181
            next if @cmd_exclude[cmd]
 
182
            out.puts
 
183
            out.puts ".TP #{ManIndent}"
 
184
            write_command(out, cmd)
 
185
          end
 
186
          # Now blacklist the group
 
187
          @group_exclude[group] = true
 
188
        end
 
189
 
 
190
        def write_command(out, cmd)
 
191
          write_command_signature(out, cmd)
 
192
          write_command_description(out, cmd)
 
193
          out.puts ".br"
 
194
          write_command_options(out, cmd)
 
195
          out.puts ".br"
 
196
          write_corresponding_command(out, cmd)
 
197
        end
 
198
 
 
199
        # Writes a signature (ie the option specification) for the
 
200
        # command
 
201
        def write_command_signature(out, cmd)
 
202
          short, long, dummy = cmd.option_strings
 
203
          long, *args = long.split(/\s+/)
 
204
          args = " \\fI#{args.join(' ')}\\fR"
 
205
          out.puts ".B %s%s%s%s" % [ short, (short ? ", " : ""), long, args ]
 
206
          # Blacklist commands whose signature we wrote.
 
207
          @cmd_exclude[cmd] = true
 
208
        end
 
209
 
 
210
 
 
211
        # Returns the description for the command
 
212
        def write_command_description(out, cmd)
 
213
          mup = MarkedUpText.new(@doc, cmd.long_description)
 
214
          out.puts markup_to_man(mup.elements)
 
215
        end
 
216
 
 
217
        # Displays the optional arguments for the given command
 
218
        def write_command_options(out, cmd)
 
219
          if cmd.has_options?
 
220
            # .map {|x| "/#{x}="} ??? Does not seem to help much
 
221
            options = cmd.optional_arguments.keys.sort.join(' ')
 
222
            out.puts ".B Optional arguments:\n.I #{options}"
 
223
          end
 
224
        end
 
225
 
 
226
        # Displays the corresponding 'file' command
 
227
        def write_corresponding_command(out, cmd)
 
228
          arguments = cmd.arguments.map {|a| a.displayed_name}.join(',')
 
229
          if cmd.has_options?
 
230
            arguments += ",option=..." 
 
231
          end
 
232
          out.puts ".B Corresponding command:\n.I #{cmd.name}(#{arguments})"
 
233
        end
 
234
 
 
235
        # Writes documentation about all the types known to ctioga.
 
236
        def write_types(out)
 
237
          first = true
 
238
          for n, t in @doc.types.sort
 
239
            write_type(out,t, first ? "8" : "")
 
240
            first = false
 
241
          end
 
242
        end
 
243
        
 
244
        def write_type(out, type, indent = "")
 
245
          out.puts ".TP #{indent}"
 
246
          out.puts ".I #{type.name}"
 
247
          out.puts markup_to_man(type.description)
 
248
        end
 
249
 
 
250
        # Returns the header string
 
251
        def header_string(version, file)
 
252
          return ManualPageHeader % [ file, 
 
253
                                      CTioga2::Version::last_modified_date, 
 
254
                                      version ]
 
255
        end
 
256
 
 
257
        ManualPageHeader = <<'EOF'
 
258
.\" This is the manual page for ctioga2
 
259
.\"
 
260
.\" Copyright 2009 by Vincent Fourmond
 
261
.\"
 
262
.\" This file is generated from the ctioga2 code and from the file %s
 
263
.\"
 
264
.\" This program is free software; you can redistribute it and/or modify
 
265
.\" it under the terms of the GNU General Public License as published by
 
266
.\" the Free Software Foundation; either version 2 of the License, or
 
267
.\" (at your option) any later version.
 
268
.\"  
 
269
.\" This program is distributed in the hope that it will be useful,
 
270
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
 
271
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
272
.\" GNU General Public License for more details (in the COPYING file).
 
273
.\"
 
274
.TH CTIOGA2 1 "%s" "Version %s" "Command-line interface for Tioga"
 
275
EOF
 
276
 
 
277
      end
 
278
    end
 
279
 
 
280
  end
 
281
end