~ubuntu-branches/ubuntu/trusty/ruby1.9/trusty

« back to all changes in this revision

Viewing changes to lib/rdoc/markup/simple_markup/fragments.rb

  • Committer: Bazaar Package Importer
  • Author(s): Stephan Hermann
  • Date: 2008-05-16 12:37:06 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20080516123706-r4llcdfd35aobrjv
Tags: 1.9.0.1-1ubuntu1
* Merge from debian unstable, remaining changes:
  - Robustify check for target_os, fixing build failure on lpia.
* debian/control:
  - ruby1.9 pkg: moved rdoc1.9 suggestion to depends. (LP: #228345)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
require 'rdoc/markup/simple_markup/lines.rb'
2
 
#require 'rdoc/markup/simple_markup/to_flow.rb'
3
 
 
4
 
module SM
5
 
 
6
 
  ##
7
 
  # A Fragment is a chunk of text, subclassed as a paragraph, a list
8
 
  # entry, or verbatim text
9
 
 
10
 
  class Fragment
11
 
    attr_reader   :level, :param, :txt
12
 
    attr_accessor :type
13
 
 
14
 
    def initialize(level, param, type, txt)
15
 
      @level = level
16
 
      @param = param
17
 
      @type  = type
18
 
      @txt   = ""
19
 
      add_text(txt) if txt
20
 
    end
21
 
 
22
 
    def add_text(txt)
23
 
      @txt << " " if @txt.length > 0
24
 
      @txt << txt.tr_s("\n ", "  ").strip
25
 
    end
26
 
 
27
 
    def to_s
28
 
      "L#@level: #{self.class.name.split('::')[-1]}\n#@txt"
29
 
    end
30
 
 
31
 
    ######
32
 
    # This is a simple factory system that lets us associate fragement
33
 
    # types (a string) with a subclass of fragment
34
 
 
35
 
    TYPE_MAP = {}
36
 
 
37
 
    def Fragment.type_name(name)
38
 
      TYPE_MAP[name] = self
39
 
    end
40
 
 
41
 
    def Fragment.for(line)
42
 
      klass =  TYPE_MAP[line.type] ||
43
 
        raise("Unknown line type: '#{line.type.inspect}:' '#{line.text}'")
44
 
      return klass.new(line.level, line.param, line.flag, line.text)
45
 
    end
46
 
  end
47
 
 
48
 
  ##
49
 
  # A paragraph is a fragment which gets wrapped to fit. We remove all
50
 
  # newlines when we're created, and have them put back on output
51
 
 
52
 
  class Paragraph < Fragment
53
 
    type_name Line::PARAGRAPH
54
 
  end
55
 
 
56
 
  class BlankLine < Paragraph
57
 
    type_name Line::BLANK
58
 
  end
59
 
 
60
 
  class Heading < Paragraph
61
 
    type_name Line::HEADING
62
 
 
63
 
    def head_level
64
 
      @param.to_i
65
 
    end
66
 
  end
67
 
 
68
 
  ##
69
 
  # A List is a fragment with some kind of label
70
 
  #
71
 
 
72
 
  class ListBase < Paragraph
73
 
    # List types
74
 
    BULLET  = :BULLET
75
 
    NUMBER  = :NUMBER
76
 
    UPPERALPHA  = :UPPERALPHA
77
 
    LOWERALPHA  = :LOWERALPHA
78
 
    LABELED = :LABELED
79
 
    NOTE    = :NOTE
80
 
  end
81
 
 
82
 
  class ListItem < ListBase
83
 
    type_name Line::LIST
84
 
 
85
 
    #  def label
86
 
    #    am = AttributeManager.new(@param)
87
 
    #    am.flow
88
 
    #  end
89
 
  end
90
 
 
91
 
  class ListStart < ListBase
92
 
    def initialize(level, param, type)
93
 
      super(level, param, type, nil)
94
 
    end
95
 
  end
96
 
 
97
 
  class ListEnd < ListBase
98
 
    def initialize(level, type)
99
 
      super(level, "", type, nil)
100
 
    end
101
 
  end
102
 
 
103
 
  ##
104
 
  # Verbatim code contains lines that don't get wrapped.
105
 
 
106
 
  class Verbatim < Fragment
107
 
    type_name  Line::VERBATIM
108
 
 
109
 
    def add_text(txt)
110
 
      @txt << txt.chomp << "\n"
111
 
    end
112
 
 
113
 
  end
114
 
 
115
 
  ##
116
 
  # A horizontal rule
117
 
  class Rule < Fragment
118
 
    type_name Line::RULE
119
 
  end
120
 
 
121
 
 
122
 
  # Collect groups of lines together. Each group
123
 
  # will end up containing a flow of text
124
 
 
125
 
  class LineCollection
126
 
    
127
 
    def initialize
128
 
      @fragments = []
129
 
    end
130
 
 
131
 
    def add(fragment)
132
 
      @fragments << fragment
133
 
    end
134
 
 
135
 
    def each(&b)
136
 
      @fragments.each(&b)
137
 
    end
138
 
 
139
 
    # For testing
140
 
    def to_a
141
 
      @fragments.map {|fragment| fragment.to_s}
142
 
    end
143
 
 
144
 
    # Factory for different fragment types
145
 
    def fragment_for(*args)
146
 
      Fragment.for(*args)
147
 
    end
148
 
 
149
 
    # tidy up at the end
150
 
    def normalize
151
 
      change_verbatim_blank_lines
152
 
      add_list_start_and_ends
153
 
      add_list_breaks
154
 
      tidy_blank_lines
155
 
    end
156
 
 
157
 
    def to_s
158
 
      @fragments.join("\n----\n")
159
 
    end
160
 
 
161
 
    def accept(am, visitor)
162
 
 
163
 
      visitor.start_accepting
164
 
 
165
 
      @fragments.each do |fragment|
166
 
        case fragment
167
 
        when Verbatim
168
 
          visitor.accept_verbatim(am, fragment)
169
 
        when Rule
170
 
          visitor.accept_rule(am, fragment)
171
 
        when ListStart
172
 
          visitor.accept_list_start(am, fragment)
173
 
        when ListEnd
174
 
          visitor.accept_list_end(am, fragment)
175
 
        when ListItem
176
 
          visitor.accept_list_item(am, fragment)
177
 
        when BlankLine
178
 
          visitor.accept_blank_line(am, fragment)
179
 
        when Heading
180
 
          visitor.accept_heading(am, fragment)
181
 
        when Paragraph
182
 
          visitor.accept_paragraph(am, fragment)
183
 
        end
184
 
      end
185
 
 
186
 
      visitor.end_accepting
187
 
    end
188
 
    #######
189
 
    private
190
 
    #######
191
 
 
192
 
    # If you have:
193
 
    #
194
 
    #    normal paragraph text.
195
 
    #
196
 
    #       this is code
197
 
    #   
198
 
    #       and more code
199
 
    #
200
 
    # You'll end up with the fragments Paragraph, BlankLine, 
201
 
    # Verbatim, BlankLine, Verbatim, BlankLine, etc
202
 
    #
203
 
    # The BlankLine in the middle of the verbatim chunk needs to
204
 
    # be changed to a real verbatim newline, and the two
205
 
    # verbatim blocks merged
206
 
    #
207
 
    #    
208
 
    def change_verbatim_blank_lines
209
 
      frag_block = nil
210
 
      blank_count = 0
211
 
      @fragments.each_with_index do |frag, i|
212
 
        if frag_block.nil?
213
 
          frag_block = frag if Verbatim === frag
214
 
        else
215
 
          case frag
216
 
          when Verbatim
217
 
            blank_count.times { frag_block.add_text("\n") }
218
 
            blank_count = 0
219
 
            frag_block.add_text(frag.txt)
220
 
            @fragments[i] = nil    # remove out current fragment
221
 
          when BlankLine
222
 
            if frag_block
223
 
              blank_count += 1
224
 
              @fragments[i] = nil
225
 
            end
226
 
          else
227
 
            frag_block = nil
228
 
            blank_count = 0
229
 
          end
230
 
        end
231
 
      end
232
 
      @fragments.compact!
233
 
    end
234
 
 
235
 
    # List nesting is implicit given the level of
236
 
    # Make it explicit, just to make life a tad
237
 
    # easier for the output processors
238
 
 
239
 
    def add_list_start_and_ends
240
 
      level = 0
241
 
      res = []
242
 
      type_stack = []
243
 
 
244
 
      @fragments.each do |fragment|
245
 
        # $stderr.puts "#{level} : #{fragment.class.name} : #{fragment.level}"
246
 
        new_level = fragment.level
247
 
        while (level < new_level)
248
 
          level += 1
249
 
          type = fragment.type
250
 
          res << ListStart.new(level, fragment.param, type) if type
251
 
          type_stack.push type
252
 
          # $stderr.puts "Start: #{level}"
253
 
        end
254
 
 
255
 
        while level > new_level
256
 
          type = type_stack.pop
257
 
          res << ListEnd.new(level, type) if type
258
 
          level -= 1
259
 
          # $stderr.puts "End: #{level}, #{type}"
260
 
        end
261
 
 
262
 
        res << fragment
263
 
        level = fragment.level
264
 
      end
265
 
      level.downto(1) do |i|
266
 
        type = type_stack.pop
267
 
        res << ListEnd.new(i, type) if type
268
 
      end
269
 
 
270
 
      @fragments = res
271
 
    end
272
 
 
273
 
    # now insert start/ends between list entries at the
274
 
    # same level that have different element types
275
 
 
276
 
    def add_list_breaks
277
 
      res = @fragments
278
 
 
279
 
      @fragments = []
280
 
      list_stack = []
281
 
 
282
 
      res.each do |fragment|
283
 
        case fragment
284
 
        when ListStart
285
 
          list_stack.push fragment
286
 
        when ListEnd
287
 
          start = list_stack.pop
288
 
          fragment.type = start.type
289
 
        when ListItem
290
 
          l = list_stack.last
291
 
          if fragment.type != l.type
292
 
            @fragments << ListEnd.new(l.level, l.type)
293
 
            start = ListStart.new(l.level, fragment.param, fragment.type)
294
 
            @fragments << start
295
 
            list_stack.pop
296
 
            list_stack.push start
297
 
          end
298
 
        else
299
 
          ;
300
 
        end
301
 
        @fragments << fragment
302
 
      end
303
 
    end
304
 
 
305
 
    # Finally tidy up the blank lines:
306
 
    # * change Blank/ListEnd into ListEnd/Blank
307
 
    # * remove blank lines at the front
308
 
 
309
 
    def tidy_blank_lines
310
 
      (@fragments.size - 1).times do |i|
311
 
        if @fragments[i].kind_of?(BlankLine) and 
312
 
            @fragments[i+1].kind_of?(ListEnd)
313
 
          @fragments[i], @fragments[i+1] = @fragments[i+1], @fragments[i] 
314
 
        end
315
 
      end
316
 
 
317
 
      # remove leading blanks
318
 
      @fragments.each_with_index do |f, i|
319
 
        break unless f.kind_of? BlankLine
320
 
        @fragments[i] = nil
321
 
      end
322
 
 
323
 
      @fragments.compact!
324
 
    end
325
 
 
326
 
  end
327
 
  
328
 
end