fxri 0.3.4 → 0.3.5

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.
@@ -1,63 +1,63 @@
1
- # Copyright (c) 2004, 2005 Martin Ankerl
2
- # Shows a grey text in an FXTextField if the user did not enter any input. This is a nice way to
3
- # give the user more information about what to enter into a text field, without the need of additional
4
- # space in the GUI.
5
- class Empty_Text_Field_Handler
6
-
7
- # Create a new handler for the specified textfield, with the given text. From now on you have to use the
8
- # created object to get and set text, not the textfield or this handler would come out of sync
9
- def initialize(textField, myText)
10
- @textField = textField
11
- @myText = myText
12
- @isEmpty = true
13
- onTextFieldFocusOut
14
- # create connections
15
- @textField.connect(SEL_FOCUSIN, method(:onTextFieldFocusIn))
16
- @textField.connect(SEL_FOCUSOUT, method(:onTextFieldFocusOut))
17
- end
18
-
19
- # Check if textfield is empty (no user input).
20
- def empty?
21
- @isEmpty
22
- end
23
-
24
- # Set new text for the textfield
25
- def text=(newText)
26
- onTextFieldFocusIn
27
- @textField.text = newText.to_s
28
- onTextFieldFocusOut
29
- end
30
-
31
- # Get the textfield's text, if the user has entered something.
32
- def text
33
- if empty? && !@inside
34
- ""
35
- else
36
- @textField.text
37
- end
38
- end
39
-
40
- # Set focus to the textfield.
41
- def setFocus
42
- @textField.setFocus
43
- end
44
-
45
- private
46
-
47
- def onTextFieldFocusIn(*args)
48
- @inside = true
49
- return if !@isEmpty
50
- @textField.textColor = FXColor::Black
51
- @textField.text = ""
52
- end
53
-
54
- def onTextFieldFocusOut(*args)
55
- @inside = false
56
- @textField.killSelection
57
- @isEmpty = @textField.text == ""
58
- return if !@isEmpty
59
- @textField.textColor = FXColor::DarkGrey
60
- @textField.text = @myText
61
- @isEmpty = true
62
- end
63
- end
1
+ # Copyright (c) 2004, 2005 Martin Ankerl
2
+ # Shows a grey text in an FXTextField if the user did not enter any input. This is a nice way to
3
+ # give the user more information about what to enter into a text field, without the need of additional
4
+ # space in the GUI.
5
+ class Empty_Text_Field_Handler
6
+
7
+ # Create a new handler for the specified textfield, with the given text. From now on you have to use the
8
+ # created object to get and set text, not the textfield or this handler would come out of sync
9
+ def initialize(textField, myText)
10
+ @textField = textField
11
+ @myText = myText
12
+ @isEmpty = true
13
+ onTextFieldFocusOut
14
+ # create connections
15
+ @textField.connect(SEL_FOCUSIN, method(:onTextFieldFocusIn))
16
+ @textField.connect(SEL_FOCUSOUT, method(:onTextFieldFocusOut))
17
+ end
18
+
19
+ # Check if textfield is empty (no user input).
20
+ def empty?
21
+ @isEmpty
22
+ end
23
+
24
+ # Set new text for the textfield
25
+ def text=(newText)
26
+ onTextFieldFocusIn
27
+ @textField.text = newText.to_s
28
+ onTextFieldFocusOut
29
+ end
30
+
31
+ # Get the textfield's text, if the user has entered something.
32
+ def text
33
+ if empty? && !@inside
34
+ ""
35
+ else
36
+ @textField.text
37
+ end
38
+ end
39
+
40
+ # Set focus to the textfield.
41
+ def setFocus
42
+ @textField.setFocus
43
+ end
44
+
45
+ private
46
+
47
+ def onTextFieldFocusIn(*args)
48
+ @inside = true
49
+ return if !@isEmpty
50
+ @textField.textColor = FXColor::Black
51
+ @textField.text = ""
52
+ end
53
+
54
+ def onTextFieldFocusOut(*args)
55
+ @inside = false
56
+ @textField.killSelection
57
+ @isEmpty = @textField.text == ""
58
+ return if !@isEmpty
59
+ @textField.textColor = FXColor::DarkGrey
60
+ @textField.text = @myText
61
+ @isEmpty = true
62
+ end
63
+ end
@@ -1,148 +1,148 @@
1
- class FoxDisplayer
2
- attr_accessor :reader
3
-
4
- def initialize(text_field)
5
- @text_field = text_field
6
- @formatter = FoxTextFormatter.new(70, "") do |arg, style|
7
- startpos = @str.size
8
- @str << arg
9
- @formats.push [startpos, arg.size, style]
10
- end
11
- @reader = nil
12
- end
13
-
14
- def width=(newWidth)
15
- @formatter.width = newWidth
16
- end
17
-
18
- def no_info_available
19
- @text_field.text="nothing here, move on!"
20
- end
21
-
22
- def init_text
23
- @str = ""
24
- @formats = Array.new
25
- end
26
-
27
- # Sets a new text, and all styles
28
- def set_text
29
- @text_field.text = @str
30
- @formats.each do |start, n, style|
31
- case style
32
- when FoxTextFormatter::STYLE_BOLD
33
- @text_field.changeStyle(start, n, 2)
34
- when FoxTextFormatter::STYLE_H1
35
- @text_field.changeStyle(start, n, 3)
36
- when FoxTextFormatter::STYLE_H2
37
- @text_field.changeStyle(start, n, 4)
38
- when FoxTextFormatter::STYLE_H3
39
- @text_field.changeStyle(start, n, 5)
40
- when FoxTextFormatter::STYLE_TELETYPE
41
- @text_field.changeStyle(start, n, 6)
42
- when FoxTextFormatter::STYLE_CODE
43
- @text_field.changeStyle(start, n, 7)
44
- when FoxTextFormatter::STYLE_EMPHASIS
45
- @text_field.changeStyle(start, n, 8)
46
- when FoxTextFormatter::STYLE_CLASS
47
- @text_field.changeStyle(start, n, 9)
48
- else
49
- @text_field.changeStyle(start, n, 1)
50
- end
51
-
52
- end
53
- end
54
-
55
- # Display method information
56
- def display_method_info(method)
57
- init_text
58
- @formatter.draw_line(method.full_name)
59
- @formatter.display_params(method)
60
- @formatter.draw_line
61
- display_flow(method.comment)
62
-
63
- if method.aliases && !method.aliases.empty?
64
- @formatter.blankline
65
- aka = "(also known as "
66
- aka << method.aliases.map {|a| a.name }.join(", ")
67
- aka << ")"
68
- @formatter.wrap(aka)
69
- end
70
- set_text
71
- end
72
-
73
- def display_information(message)
74
- init_text
75
- display_flow(message)
76
- set_text
77
- end
78
-
79
- def display_class_info(klass)
80
- init_text
81
- superclass = klass.superclass_string
82
- if superclass
83
- superclass = " < " + superclass
84
- else
85
- superclass = ""
86
- end
87
- @formatter.draw_line(klass.display_name + ": " + klass.full_name + superclass)
88
- display_flow(klass.comment)
89
- @formatter.draw_line
90
-
91
- unless klass.includes.empty?
92
- @formatter.blankline
93
- @formatter.display_heading("Includes:", 2, "")
94
- incs = []
95
- klass.includes.each do |inc|
96
- inc_desc = @reader.find_class_by_name(inc.name)
97
- if inc_desc
98
- str = inc.name + "("
99
- str << inc_desc.instance_methods.map{|m| m.name}.join(", ")
100
- str << ")"
101
- incs << str
102
- else
103
- incs << inc.name
104
- end
105
- end
106
- @formatter.wrap(incs.sort.join(', '))
107
- end
108
-
109
- unless klass.constants.empty?
110
- @formatter.blankline
111
- @formatter.display_heading("Constants:", 2, "")
112
- len = 0
113
- klass.constants.each { |c| len = c.name.length if c.name.length > len }
114
- len += 2
115
- klass.constants.each do |c|
116
- @formatter.wrap(c.value, @formatter.indent+((c.name+":").ljust(len)))
117
- end
118
- end
119
-
120
- unless klass.class_methods.empty?
121
- @formatter.blankline
122
- @formatter.display_heading("Class methods:", 2, "")
123
- @formatter.wrap(klass.class_methods.map{|m| m.name}.sort.join(', '))
124
- end
125
-
126
- unless klass.instance_methods.empty?
127
- @formatter.blankline
128
- @formatter.display_heading("Instance methods:", 2, "")
129
- @formatter.wrap(klass.instance_methods.map{|m| m.name}.sort.join(', '))
130
- end
131
-
132
- unless klass.attributes.empty?
133
- @formatter.blankline
134
- @formatter.wrap("Attributes:", "")
135
- @formatter.wrap(klass.attributes.map{|a| a.name}.sort.join(', '))
136
- end
137
-
138
- set_text
139
- end
140
-
141
- def display_flow(flow)
142
- if !flow || flow.empty?
143
- @formatter.wrap("(no description...)\n")
144
- else
145
- @formatter.display_flow(flow)
146
- end
147
- end
148
- end
1
+ class FoxDisplayer
2
+ attr_accessor :reader
3
+
4
+ def initialize(text_field)
5
+ @text_field = text_field
6
+ @formatter = FoxTextFormatter.new(70, "") do |arg, style|
7
+ startpos = @str.size
8
+ @str << arg
9
+ @formats.push [startpos, arg.size, style]
10
+ end
11
+ @reader = nil
12
+ end
13
+
14
+ def width=(newWidth)
15
+ @formatter.width = newWidth
16
+ end
17
+
18
+ def no_info_available
19
+ @text_field.text="nothing here, move on!"
20
+ end
21
+
22
+ def init_text
23
+ @str = ""
24
+ @formats = Array.new
25
+ end
26
+
27
+ # Sets a new text, and all styles
28
+ def set_text
29
+ @text_field.text = @str
30
+ @formats.each do |start, n, style|
31
+ case style
32
+ when FoxTextFormatter::STYLE_BOLD
33
+ @text_field.changeStyle(start, n, 2)
34
+ when FoxTextFormatter::STYLE_H1
35
+ @text_field.changeStyle(start, n, 3)
36
+ when FoxTextFormatter::STYLE_H2
37
+ @text_field.changeStyle(start, n, 4)
38
+ when FoxTextFormatter::STYLE_H3
39
+ @text_field.changeStyle(start, n, 5)
40
+ when FoxTextFormatter::STYLE_TELETYPE
41
+ @text_field.changeStyle(start, n, 6)
42
+ when FoxTextFormatter::STYLE_CODE
43
+ @text_field.changeStyle(start, n, 7)
44
+ when FoxTextFormatter::STYLE_EMPHASIS
45
+ @text_field.changeStyle(start, n, 8)
46
+ when FoxTextFormatter::STYLE_CLASS
47
+ @text_field.changeStyle(start, n, 9)
48
+ else
49
+ @text_field.changeStyle(start, n, 1)
50
+ end
51
+
52
+ end
53
+ end
54
+
55
+ # Display method information
56
+ def display_method_info(method)
57
+ init_text
58
+ @formatter.draw_line(method.full_name)
59
+ @formatter.display_params(method)
60
+ @formatter.draw_line
61
+ display_flow(method.comment)
62
+
63
+ if method.aliases && !method.aliases.empty?
64
+ @formatter.blankline
65
+ aka = "(also known as "
66
+ aka << method.aliases.map {|a| a.name }.join(", ")
67
+ aka << ")"
68
+ @formatter.wrap(aka)
69
+ end
70
+ set_text
71
+ end
72
+
73
+ def display_information(message)
74
+ init_text
75
+ display_flow(message)
76
+ set_text
77
+ end
78
+
79
+ def display_class_info(klass)
80
+ init_text
81
+ superclass = klass.superclass_string
82
+ if superclass
83
+ superclass = " < " + superclass
84
+ else
85
+ superclass = ""
86
+ end
87
+ @formatter.draw_line(klass.display_name + ": " + klass.full_name + superclass)
88
+ display_flow(klass.comment)
89
+ @formatter.draw_line
90
+
91
+ unless klass.includes.empty?
92
+ @formatter.blankline
93
+ @formatter.display_heading("Includes:", 2, "")
94
+ incs = []
95
+ klass.includes.each do |inc|
96
+ inc_desc = @reader.find_class_by_name(inc.name)
97
+ if inc_desc
98
+ str = inc.name + "("
99
+ str << inc_desc.instance_methods.map{|m| m.name}.join(", ")
100
+ str << ")"
101
+ incs << str
102
+ else
103
+ incs << inc.name
104
+ end
105
+ end
106
+ @formatter.wrap(incs.sort.join(', '))
107
+ end
108
+
109
+ unless klass.constants.empty?
110
+ @formatter.blankline
111
+ @formatter.display_heading("Constants:", 2, "")
112
+ len = 0
113
+ klass.constants.each { |c| len = c.name.length if c.name.length > len }
114
+ len += 2
115
+ klass.constants.each do |c|
116
+ @formatter.wrap(c.value, @formatter.indent+((c.name+":").ljust(len)))
117
+ end
118
+ end
119
+
120
+ unless klass.class_methods.empty?
121
+ @formatter.blankline
122
+ @formatter.display_heading("Class methods:", 2, "")
123
+ @formatter.wrap(klass.class_methods.map{|m| m.name}.sort.join(', '))
124
+ end
125
+
126
+ unless klass.instance_methods.empty?
127
+ @formatter.blankline
128
+ @formatter.display_heading("Instance methods:", 2, "")
129
+ @formatter.wrap(klass.instance_methods.map{|m| m.name}.sort.join(', '))
130
+ end
131
+
132
+ unless klass.attributes.empty?
133
+ @formatter.blankline
134
+ @formatter.wrap("Attributes:", "")
135
+ @formatter.wrap(klass.attributes.map{|a| a.name}.sort.join(', '))
136
+ end
137
+
138
+ set_text
139
+ end
140
+
141
+ def display_flow(flow)
142
+ if !flow || flow.empty?
143
+ @formatter.wrap("(no description...)\n")
144
+ else
145
+ @formatter.display_flow(flow)
146
+ end
147
+ end
148
+ end
@@ -1,275 +1,275 @@
1
- # This class is mostly copy & paste from ri_formatter.rb.
2
- # except that it always returns a string and does not print anything.
3
- class FoxTextFormatter
4
- # define all possible styles
5
- STYLE_NORMAL = :STYLE_NORMAL
6
- STYLE_BOLD = :STYLE_BOLD
7
- STYLE_CLASS = :STYLE_CLASS
8
- STYLE_H1 = :STYLE_H1
9
- STYLE_H2 = :STYLE_H2
10
- STYLE_H3 = :STYLE_H3
11
- STYLE_TELETYPE = :STYLE_TELETYPE
12
- STYLE_CODE = :STYLE_CODE
13
- STYLE_EMPHASIS = :STYLE_EMPHASIS
14
-
15
- attr_reader :indent
16
- attr_accessor :width
17
-
18
- # whenever text should be printed/added/shown, proc is called with the text as the argument.
19
- def initialize(width, indent, &proc)
20
- @width = width
21
- @indent = indent
22
- @proc = proc
23
- end
24
-
25
- ######################################################################
26
-
27
- def draw_line(label=nil)
28
- len = @width
29
- len -= (label.size+1) if label
30
- len = [0, len].max
31
- @proc.call("-"*len)
32
- if label
33
- @proc.call(" ")
34
- @proc.call(label, STYLE_CLASS)
35
- end
36
- @proc.call("\n")
37
- end
38
-
39
- def display_params(method)
40
- params = method.params
41
-
42
- if params[0] == ?(
43
- if method.is_singleton
44
- params = method.full_name + params
45
- else
46
- params = method.name + params
47
- end
48
- end
49
- params.split(/\n/).each do |param|
50
- @proc.call(param+"\n", STYLE_BOLD)
51
- end
52
- end
53
-
54
- def wrap(txt, prefix=@indent, linelen=@width)
55
- return if !txt || txt.empty?
56
- @proc.call(prefix, STYLE_EMPHASIS)
57
- conv_markup(txt, prefix, linelen)
58
- =begin
59
- textLen = linelen - prefix.length
60
- patt = Regexp.new("^(.{0,#{textLen}})[ \n]")
61
- next_prefix = prefix.tr("^ ", " ")
62
-
63
- res = []
64
-
65
- while work.length > textLen
66
- if work =~ patt
67
- res << $1
68
- work.slice!(0, $&.length)
69
- else
70
- res << work.slice!(0, textLen)
71
- end
72
- end
73
- res << work if work.length.nonzero?
74
- @proc.call(prefix + res.join("\n" + next_prefix) + "\n")
75
- =end
76
- end
77
-
78
- ######################################################################
79
-
80
- def blankline
81
- @proc.call("\n")
82
- end
83
-
84
- ######################################################################
85
-
86
- # called when we want to ensure a nbew 'wrap' starts on a newline
87
- # Only needed for HtmlFormatter, because the rest do their
88
- # own line breaking
89
-
90
- def break_to_newline
91
- end
92
-
93
- ######################################################################
94
-
95
- def bold_print(txt)
96
- @proc.call(txt, STYLE_BOLD)
97
- end
98
-
99
- ######################################################################
100
-
101
- def raw_print_line(txt)
102
- @proc.call(txt)
103
- end
104
-
105
- ######################################################################
106
-
107
- # convert HTML entities back to ASCII
108
- def conv_html(txt)
109
- case txt
110
- when Array
111
- txt.join.
112
- gsub(/&gt;/, '>').
113
- gsub(/&lt;/, '<').
114
- gsub(/&quot;/, '"').
115
- gsub(/&amp;/, '&')
116
- else # it's a String
117
- txt.
118
- gsub(/&gt;/, '>').
119
- gsub(/&lt;/, '<').
120
- gsub(/&quot;/, '"').
121
- gsub(/&amp;/, '&')
122
- end
123
- end
124
-
125
- # convert markup into display form
126
- def conv_markup(txt, prefix, linelen)
127
-
128
- # this code assumes that tags are not used inside tags
129
- pos = 0
130
- old_pos = 0
131
- style = STYLE_NORMAL
132
- current_indent = prefix.size
133
- while pos = txt.index(%r{(<tt>|<code>|<b>|<em>|</tt>|</code>|</b>|</em>)}, old_pos)
134
- new_part = txt[old_pos...pos]
135
- @proc.call(new_part, style)
136
-
137
- # get tag name
138
- old_pos = txt.index(">", pos) + 1
139
- style = case txt[(pos+1)...(old_pos-1)]
140
- when "tt"
141
- STYLE_TELETYPE
142
- when "code"
143
- STYLE_CODE
144
- when "b"
145
- STYLE_BOLD
146
- when "em"
147
- STYLE_EMPHASIS
148
- else
149
- # closing or unknown tags
150
- STYLE_NORMAL
151
- end
152
- end
153
- @proc.call(txt[old_pos...txt.size], style)
154
- @proc.call("\n")
155
- end
156
-
157
- ######################################################################
158
-
159
- def display_list(list)
160
- case list.type
161
- when SM::ListBase::BULLET
162
- prefixer = proc { |ignored| @indent + "* " }
163
-
164
- when SM::ListBase::NUMBER,
165
- SM::ListBase::UPPERALPHA,
166
- SM::ListBase::LOWERALPHA
167
-
168
- start = case list.type
169
- when SM::ListBase::NUMBER then 1
170
- when SM::ListBase::UPPERALPHA then 'A'
171
- when SM::ListBase::LOWERALPHA then 'a'
172
- end
173
- prefixer = proc do |ignored|
174
- res = @indent + "#{start}.".ljust(4)
175
- start = start.succ
176
- res
177
- end
178
-
179
- when SM::ListBase::LABELED
180
- prefixer = proc do |li|
181
- li.label
182
- end
183
-
184
- when SM::ListBase::NOTE
185
- longest = 0
186
- list.contents.each do |item|
187
- if item.kind_of?(SM::Flow::LI) && item.label.length > longest
188
- longest = item.label.length
189
- end
190
- end
191
-
192
- prefixer = proc do |li|
193
- @indent + li.label.ljust(longest+1)
194
- end
195
-
196
- else
197
- fail "unknown list type"
198
- end
199
-
200
- list.contents.each do |item|
201
- if item.kind_of? SM::Flow::LI
202
- prefix = prefixer.call(item)
203
- display_flow_item(item, prefix)
204
- else
205
- display_flow_item(item)
206
- end
207
- end
208
- end
209
-
210
- ######################################################################
211
-
212
- def display_flow_item(item, prefix=@indent)
213
-
214
- case item
215
- when SM::Flow::P, SM::Flow::LI
216
- wrap(conv_html(item.body), prefix)
217
- blankline
218
-
219
- when SM::Flow::LIST
220
- display_list(item)
221
-
222
- when SM::Flow::VERB
223
- display_verbatim_flow_item(item, @indent)
224
-
225
- when SM::Flow::H
226
- display_heading(conv_html(item.text), item.level, @indent)
227
-
228
- when SM::Flow::RULE
229
- draw_line
230
-
231
- when String
232
- wrap(conv_html(item), prefix)
233
-
234
- else
235
- fail "Unknown flow element: #{item.class}"
236
- end
237
- end
238
-
239
- ######################################################################
240
-
241
- def display_verbatim_flow_item(item, prefix=@indent)
242
- item.body.split(/\n/).each do |line|
243
- @proc.call(@indent)
244
- @proc.call(conv_html(line))
245
- @proc.call("\n")
246
- end
247
- blankline
248
- end
249
-
250
- ######################################################################
251
-
252
- def display_heading(text, level, indent)
253
- case level
254
- when 1
255
- @proc.call(text, STYLE_H1)
256
- @proc.call("\n")
257
-
258
- when 2
259
- @proc.call(text, STYLE_H2)
260
- @proc.call("\n")
261
-
262
- else
263
- @proc.call(indent)
264
- @proc.call(text, STYLE_H3)
265
- @proc.call("\n")
266
- end
267
- end
268
-
269
-
270
- def display_flow(flow)
271
- flow.each do |f|
272
- display_flow_item(f)
273
- end
274
- end
1
+ # This class is mostly copy & paste from ri_formatter.rb.
2
+ # except that it always returns a string and does not print anything.
3
+ class FoxTextFormatter
4
+ # define all possible styles
5
+ STYLE_NORMAL = :STYLE_NORMAL
6
+ STYLE_BOLD = :STYLE_BOLD
7
+ STYLE_CLASS = :STYLE_CLASS
8
+ STYLE_H1 = :STYLE_H1
9
+ STYLE_H2 = :STYLE_H2
10
+ STYLE_H3 = :STYLE_H3
11
+ STYLE_TELETYPE = :STYLE_TELETYPE
12
+ STYLE_CODE = :STYLE_CODE
13
+ STYLE_EMPHASIS = :STYLE_EMPHASIS
14
+
15
+ attr_reader :indent
16
+ attr_accessor :width
17
+
18
+ # whenever text should be printed/added/shown, proc is called with the text as the argument.
19
+ def initialize(width, indent, &proc)
20
+ @width = width
21
+ @indent = indent
22
+ @proc = proc
23
+ end
24
+
25
+ ######################################################################
26
+
27
+ def draw_line(label=nil)
28
+ len = @width
29
+ len -= (label.size+1) if label
30
+ len = [0, len].max
31
+ @proc.call("-"*len)
32
+ if label
33
+ @proc.call(" ")
34
+ @proc.call(label, STYLE_CLASS)
35
+ end
36
+ @proc.call("\n")
37
+ end
38
+
39
+ def display_params(method)
40
+ params = method.params
41
+
42
+ if params[0] == ?(
43
+ if method.is_singleton
44
+ params = method.full_name + params
45
+ else
46
+ params = method.name + params
47
+ end
48
+ end
49
+ params.split(/\n/).each do |param|
50
+ @proc.call(param+"\n", STYLE_BOLD)
51
+ end
52
+ end
53
+
54
+ def wrap(txt, prefix=@indent, linelen=@width)
55
+ return if !txt || txt.empty?
56
+ @proc.call(prefix, STYLE_EMPHASIS)
57
+ conv_markup(txt, prefix, linelen)
58
+ =begin
59
+ textLen = linelen - prefix.length
60
+ patt = Regexp.new("^(.{0,#{textLen}})[ \n]")
61
+ next_prefix = prefix.tr("^ ", " ")
62
+
63
+ res = []
64
+
65
+ while work.length > textLen
66
+ if work =~ patt
67
+ res << $1
68
+ work.slice!(0, $&.length)
69
+ else
70
+ res << work.slice!(0, textLen)
71
+ end
72
+ end
73
+ res << work if work.length.nonzero?
74
+ @proc.call(prefix + res.join("\n" + next_prefix) + "\n")
75
+ =end
76
+ end
77
+
78
+ ######################################################################
79
+
80
+ def blankline
81
+ @proc.call("\n")
82
+ end
83
+
84
+ ######################################################################
85
+
86
+ # called when we want to ensure a nbew 'wrap' starts on a newline
87
+ # Only needed for HtmlFormatter, because the rest do their
88
+ # own line breaking
89
+
90
+ def break_to_newline
91
+ end
92
+
93
+ ######################################################################
94
+
95
+ def bold_print(txt)
96
+ @proc.call(txt, STYLE_BOLD)
97
+ end
98
+
99
+ ######################################################################
100
+
101
+ def raw_print_line(txt)
102
+ @proc.call(txt)
103
+ end
104
+
105
+ ######################################################################
106
+
107
+ # convert HTML entities back to ASCII
108
+ def conv_html(txt)
109
+ case txt
110
+ when Array
111
+ txt.join.
112
+ gsub(/&gt;/, '>').
113
+ gsub(/&lt;/, '<').
114
+ gsub(/&quot;/, '"').
115
+ gsub(/&amp;/, '&')
116
+ else # it's a String
117
+ txt.
118
+ gsub(/&gt;/, '>').
119
+ gsub(/&lt;/, '<').
120
+ gsub(/&quot;/, '"').
121
+ gsub(/&amp;/, '&')
122
+ end
123
+ end
124
+
125
+ # convert markup into display form
126
+ def conv_markup(txt, prefix, linelen)
127
+
128
+ # this code assumes that tags are not used inside tags
129
+ pos = 0
130
+ old_pos = 0
131
+ style = STYLE_NORMAL
132
+ current_indent = prefix.size
133
+ while pos = txt.index(%r{(<tt>|<code>|<b>|<em>|</tt>|</code>|</b>|</em>)}, old_pos)
134
+ new_part = txt[old_pos...pos]
135
+ @proc.call(new_part, style)
136
+
137
+ # get tag name
138
+ old_pos = txt.index(">", pos) + 1
139
+ style = case txt[(pos+1)...(old_pos-1)]
140
+ when "tt"
141
+ STYLE_TELETYPE
142
+ when "code"
143
+ STYLE_CODE
144
+ when "b"
145
+ STYLE_BOLD
146
+ when "em"
147
+ STYLE_EMPHASIS
148
+ else
149
+ # closing or unknown tags
150
+ STYLE_NORMAL
151
+ end
152
+ end
153
+ @proc.call(txt[old_pos...txt.size], style)
154
+ @proc.call("\n")
155
+ end
156
+
157
+ ######################################################################
158
+
159
+ def display_list(list)
160
+ case list.type
161
+ when SM::ListBase::BULLET
162
+ prefixer = proc { |ignored| @indent + "* " }
163
+
164
+ when SM::ListBase::NUMBER,
165
+ SM::ListBase::UPPERALPHA,
166
+ SM::ListBase::LOWERALPHA
167
+
168
+ start = case list.type
169
+ when SM::ListBase::NUMBER then 1
170
+ when SM::ListBase::UPPERALPHA then 'A'
171
+ when SM::ListBase::LOWERALPHA then 'a'
172
+ end
173
+ prefixer = proc do |ignored|
174
+ res = @indent + "#{start}.".ljust(4)
175
+ start = start.succ
176
+ res
177
+ end
178
+
179
+ when SM::ListBase::LABELED
180
+ prefixer = proc do |li|
181
+ li.label
182
+ end
183
+
184
+ when SM::ListBase::NOTE
185
+ longest = 0
186
+ list.contents.each do |item|
187
+ if item.kind_of?(SM::Flow::LI) && item.label.length > longest
188
+ longest = item.label.length
189
+ end
190
+ end
191
+
192
+ prefixer = proc do |li|
193
+ @indent + li.label.ljust(longest+1)
194
+ end
195
+
196
+ else
197
+ fail "unknown list type"
198
+ end
199
+
200
+ list.contents.each do |item|
201
+ if item.kind_of? SM::Flow::LI
202
+ prefix = prefixer.call(item)
203
+ display_flow_item(item, prefix)
204
+ else
205
+ display_flow_item(item)
206
+ end
207
+ end
208
+ end
209
+
210
+ ######################################################################
211
+
212
+ def display_flow_item(item, prefix=@indent)
213
+
214
+ case item
215
+ when SM::Flow::P, SM::Flow::LI
216
+ wrap(conv_html(item.body), prefix)
217
+ blankline
218
+
219
+ when SM::Flow::LIST
220
+ display_list(item)
221
+
222
+ when SM::Flow::VERB
223
+ display_verbatim_flow_item(item, @indent)
224
+
225
+ when SM::Flow::H
226
+ display_heading(conv_html(item.text), item.level, @indent)
227
+
228
+ when SM::Flow::RULE
229
+ draw_line
230
+
231
+ when String
232
+ wrap(conv_html(item), prefix)
233
+
234
+ else
235
+ fail "Unknown flow element: #{item.class}"
236
+ end
237
+ end
238
+
239
+ ######################################################################
240
+
241
+ def display_verbatim_flow_item(item, prefix=@indent)
242
+ item.body.split(/\n/).each do |line|
243
+ @proc.call(@indent)
244
+ @proc.call(conv_html(line))
245
+ @proc.call("\n")
246
+ end
247
+ blankline
248
+ end
249
+
250
+ ######################################################################
251
+
252
+ def display_heading(text, level, indent)
253
+ case level
254
+ when 1
255
+ @proc.call(text, STYLE_H1)
256
+ @proc.call("\n")
257
+
258
+ when 2
259
+ @proc.call(text, STYLE_H2)
260
+ @proc.call("\n")
261
+
262
+ else
263
+ @proc.call(indent)
264
+ @proc.call(text, STYLE_H3)
265
+ @proc.call("\n")
266
+ end
267
+ end
268
+
269
+
270
+ def display_flow(flow)
271
+ flow.each do |f|
272
+ display_flow_item(f)
273
+ end
274
+ end
275
275
  end