fxri 0.1.0
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/fxri +292 -0
- data/fxri.gemspec +24 -0
- data/lib/Empty_Text_Field_Handler.rb +63 -0
- data/lib/FoxDisplayer.rb +148 -0
- data/lib/FoxTextFormatter.rb +265 -0
- data/lib/Globals.rb +42 -0
- data/lib/Icon_Loader.rb +35 -0
- data/lib/Packet_Item.rb +179 -0
- data/lib/Packet_List.rb +192 -0
- data/lib/Recursive_Open_Struct.rb +233 -0
- data/lib/RiManager.rb +155 -0
- data/lib/Search_Engine.rb +165 -0
- data/lib/fxirb.rb +339 -0
- data/lib/icons/class.png +0 -0
- data/lib/icons/method.png +0 -0
- data/lib/icons/module.png +0 -0
- metadata +65 -0
@@ -0,0 +1,265 @@
|
|
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
|
+
txt.
|
110
|
+
gsub(/>/, '>').
|
111
|
+
gsub(/</, '<').
|
112
|
+
gsub(/"/, '"').
|
113
|
+
gsub(/&/, '&')
|
114
|
+
end
|
115
|
+
|
116
|
+
# convert markup into display form
|
117
|
+
def conv_markup(txt, prefix, linelen)
|
118
|
+
|
119
|
+
# this code assumes that tags are not used inside tags
|
120
|
+
pos = 0
|
121
|
+
old_pos = 0
|
122
|
+
style = STYLE_NORMAL
|
123
|
+
current_indent = prefix.size
|
124
|
+
while pos = txt.index(%r{(<tt>|<code>|<b>|<em>|</tt>|</code>|</b>|</em>)}, old_pos)
|
125
|
+
new_part = txt[old_pos...pos]
|
126
|
+
@proc.call(new_part, style)
|
127
|
+
|
128
|
+
# get tag name
|
129
|
+
old_pos = txt.index(">", pos) + 1
|
130
|
+
style = case txt[(pos+1)...(old_pos-1)]
|
131
|
+
when "tt"
|
132
|
+
STYLE_TELETYPE
|
133
|
+
when "code"
|
134
|
+
STYLE_CODE
|
135
|
+
when "b"
|
136
|
+
STYLE_BOLD
|
137
|
+
when "em"
|
138
|
+
STYLE_EMPHASIS
|
139
|
+
else
|
140
|
+
# closing or unknown tags
|
141
|
+
STYLE_NORMAL
|
142
|
+
end
|
143
|
+
end
|
144
|
+
@proc.call(txt[old_pos...txt.size], style)
|
145
|
+
@proc.call("\n")
|
146
|
+
end
|
147
|
+
|
148
|
+
######################################################################
|
149
|
+
|
150
|
+
def display_list(list)
|
151
|
+
case list.type
|
152
|
+
when SM::ListBase::BULLET
|
153
|
+
prefixer = proc { |ignored| @indent + "* " }
|
154
|
+
|
155
|
+
when SM::ListBase::NUMBER,
|
156
|
+
SM::ListBase::UPPERALPHA,
|
157
|
+
SM::ListBase::LOWERALPHA
|
158
|
+
|
159
|
+
start = case list.type
|
160
|
+
when SM::ListBase::NUMBER then 1
|
161
|
+
when SM::ListBase::UPPERALPHA then 'A'
|
162
|
+
when SM::ListBase::LOWERALPHA then 'a'
|
163
|
+
end
|
164
|
+
prefixer = proc do |ignored|
|
165
|
+
res = @indent + "#{start}.".ljust(4)
|
166
|
+
start = start.succ
|
167
|
+
res
|
168
|
+
end
|
169
|
+
|
170
|
+
when SM::ListBase::LABELED
|
171
|
+
prefixer = proc do |li|
|
172
|
+
li.label
|
173
|
+
end
|
174
|
+
|
175
|
+
when SM::ListBase::NOTE
|
176
|
+
longest = 0
|
177
|
+
list.contents.each do |item|
|
178
|
+
if item.kind_of?(SM::Flow::LI) && item.label.length > longest
|
179
|
+
longest = item.label.length
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
prefixer = proc do |li|
|
184
|
+
@indent + li.label.ljust(longest+1)
|
185
|
+
end
|
186
|
+
|
187
|
+
else
|
188
|
+
fail "unknown list type"
|
189
|
+
end
|
190
|
+
|
191
|
+
list.contents.each do |item|
|
192
|
+
if item.kind_of? SM::Flow::LI
|
193
|
+
prefix = prefixer.call(item)
|
194
|
+
display_flow_item(item, prefix)
|
195
|
+
else
|
196
|
+
display_flow_item(item)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
######################################################################
|
202
|
+
|
203
|
+
def display_flow_item(item, prefix=@indent)
|
204
|
+
case item
|
205
|
+
when SM::Flow::P, SM::Flow::LI
|
206
|
+
wrap(conv_html(item.body), prefix)
|
207
|
+
blankline
|
208
|
+
|
209
|
+
when SM::Flow::LIST
|
210
|
+
display_list(item)
|
211
|
+
|
212
|
+
when SM::Flow::VERB
|
213
|
+
display_verbatim_flow_item(item, @indent)
|
214
|
+
|
215
|
+
when SM::Flow::H
|
216
|
+
display_heading(conv_html(item.text.join), item.level, @indent)
|
217
|
+
|
218
|
+
when SM::Flow::RULE
|
219
|
+
draw_line
|
220
|
+
|
221
|
+
when String
|
222
|
+
wrap(conv_html(item), prefix)
|
223
|
+
|
224
|
+
else
|
225
|
+
fail "Unknown flow element: #{item.class}"
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
######################################################################
|
230
|
+
|
231
|
+
def display_verbatim_flow_item(item, prefix=@indent)
|
232
|
+
item.body.split(/\n/).each do |line|
|
233
|
+
@proc.call(@indent)
|
234
|
+
@proc.call(conv_html(line))
|
235
|
+
@proc.call("\n")
|
236
|
+
end
|
237
|
+
blankline
|
238
|
+
end
|
239
|
+
|
240
|
+
######################################################################
|
241
|
+
|
242
|
+
def display_heading(text, level, indent)
|
243
|
+
case level
|
244
|
+
when 1
|
245
|
+
@proc.call(text, STYLE_H1)
|
246
|
+
@proc.call("\n")
|
247
|
+
|
248
|
+
when 2
|
249
|
+
@proc.call(text, STYLE_H2)
|
250
|
+
@proc.call("\n")
|
251
|
+
|
252
|
+
else
|
253
|
+
@proc.call(indent)
|
254
|
+
@proc.call(text, STYLE_H3)
|
255
|
+
@proc.call("\n")
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
|
260
|
+
def display_flow(flow)
|
261
|
+
flow.each do |f|
|
262
|
+
display_flow_item(f)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
data/lib/Globals.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'lib/Recursive_Open_Struct'
|
2
|
+
|
3
|
+
$cfg = Recursive_Open_Struct.new
|
4
|
+
|
5
|
+
$cfg.app.name = "fxri - Instant Ruby Enlightenment"
|
6
|
+
|
7
|
+
# uses the first font that is available
|
8
|
+
$cfg.app.font.name = ["Bitstream Vera Sans", "Verdana", "Trebuchet MS", "Tahoma", "Arial"]
|
9
|
+
$cfg.ri_font = ["Bitstream Vera Sans Mono", "Courier New", "Courier"]
|
10
|
+
$cfg.app.font.size = 8
|
11
|
+
|
12
|
+
$cfg.app.width = 760
|
13
|
+
$cfg.app.height = 480
|
14
|
+
$cfg.search_delay = 0.1
|
15
|
+
$cfg.minimum_letters_per_line = 20
|
16
|
+
$cfg.packet_list_width = 160
|
17
|
+
$cfg.irb_height = 300
|
18
|
+
$cfg.status_line_update_interval = 0.1
|
19
|
+
|
20
|
+
$cfg.list.opts = ICONLIST_SINGLESELECT|ICONLIST_DETAILED|LAYOUT_FILL_X|LAYOUT_FILL_Y|ICONLIST_AUTOSIZE
|
21
|
+
|
22
|
+
# icons, are automatically loaded from Icon_Loader.
|
23
|
+
$cfg.icons.klass = "class.png"
|
24
|
+
$cfg.icons.class_method = "module.png"
|
25
|
+
$cfg.icons.instance_method = "method.png"
|
26
|
+
|
27
|
+
# all texts
|
28
|
+
$cfg.text.search = "%d / %d entries"
|
29
|
+
$cfg.text.search_field = "What do you want to know?"
|
30
|
+
$cfg.text.method_name = "name"
|
31
|
+
|
32
|
+
|
33
|
+
$cfg.text.help = %|This is <b>fxri</b>, a graphical interface to the <em>Ruby</em> documentation. Fxri comes with a search engine with quite a few features. Here are several examples:
|
34
|
+
'<em>Array</em>': Lists all classes with the name <em>Array</em>. Note that upcase words are treated case sensitive, lowercase words insensitive.
|
35
|
+
'<em>array sort</em>': Everything that contains both <em>array</em> and <em>sort</em> (case insensitive).
|
36
|
+
'<em>array -Fox</em>': Everything that contain the name <em>array</em> (case insensitive), but not <em>Fox</em> (case sensitive).
|
37
|
+
After searching just press <em>down</em> to browse the search results. Press <em>Tab</em> to move back into the search field.
|
38
|
+
If you have any questions, suggestions, problems, please contact me with <b>martin.ankerl@gmail.com</b>.|
|
39
|
+
|
40
|
+
|
41
|
+
# prevent further modifications
|
42
|
+
$cfg.close
|
data/lib/Icon_Loader.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# Copyright (c) 2004, 2005 Martin Ankerl
|
2
|
+
|
3
|
+
# Converts a Recursive_Open_Struct that contains filenames of PNG-icons into real icons.
|
4
|
+
class Icon_Loader
|
5
|
+
# Create a new Icon_Loader. You need to specify the Fox-application.
|
6
|
+
def initialize(app)
|
7
|
+
@app = app
|
8
|
+
end
|
9
|
+
|
10
|
+
# Takes each attribute of the given Recursive_Open_Struct,
|
11
|
+
# converts it into a real icon, and sets it.
|
12
|
+
def cfg_to_icons(cfg)
|
13
|
+
cfg.attrs.each do |attr|
|
14
|
+
value = cfg.send(attr.to_sym)
|
15
|
+
if (value.class == Recursive_Open_Struct)
|
16
|
+
cfg_to_icons(value)
|
17
|
+
else
|
18
|
+
# value is a filename
|
19
|
+
icon = make_icon(value)
|
20
|
+
cfg.send((attr + "=").to_sym, icon)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Constructs an icon from the given filename (from the icons directory).
|
26
|
+
def make_icon(filename)
|
27
|
+
filename = File.join("lib", "icons", filename)
|
28
|
+
icon = nil
|
29
|
+
File.open(filename, "rb") do |f|
|
30
|
+
icon = FXPNGIcon.new(@app, f.read, 0)
|
31
|
+
end
|
32
|
+
icon.create
|
33
|
+
icon
|
34
|
+
end
|
35
|
+
end
|
data/lib/Packet_Item.rb
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
# Copyright (c) 2004, 2005 Christoph Heindl and Martin Ankerl
|
2
|
+
class MutexDummy
|
3
|
+
def synchronize
|
4
|
+
yield
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
# Lock used to synchronize item removes.
|
9
|
+
# for now, a global lock is good enough.
|
10
|
+
$fx_icon_item_remove_mutex = Mutex.new
|
11
|
+
|
12
|
+
|
13
|
+
# An item for Packet_List. This is a convenient wrapper for the FXIconItem.
|
14
|
+
class Packet_Item
|
15
|
+
|
16
|
+
attr_accessor :searchable
|
17
|
+
|
18
|
+
# Fox_Item is a very thin wrapper that calles Packet_Item functionality.
|
19
|
+
class Fox_Item < FXIconItem
|
20
|
+
# optimization: directly sort by sort_key and reversed
|
21
|
+
attr_accessor :sort_key
|
22
|
+
attr_accessor :reversed
|
23
|
+
|
24
|
+
# Create a new item with packet_item as the parent. *args is passed to the FXIconItem.
|
25
|
+
def initialize(packet_item, *args)
|
26
|
+
@packet_item = packet_item
|
27
|
+
@sort_key = nil
|
28
|
+
@reversed = 1
|
29
|
+
@is_deleted = false
|
30
|
+
super(*args)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Sometimes draw is called AFTER the item has been removed.
|
34
|
+
# In this case: return immediately. Otherwise a Runtime Error would occur!
|
35
|
+
def draw(*args)
|
36
|
+
$fx_icon_item_remove_mutex.synchronize do
|
37
|
+
#puts "draw"
|
38
|
+
return if @is_deleted
|
39
|
+
super
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Mark item as deleted, to prevent execution of draw afterwards
|
44
|
+
# this is called from Packet_List which uses the same mutex
|
45
|
+
# as draw.
|
46
|
+
def deleted
|
47
|
+
@is_deleted = true
|
48
|
+
end
|
49
|
+
|
50
|
+
# Called from sortItems, uses packet_item's comparison.
|
51
|
+
def <=>(other)
|
52
|
+
(@sort_key <=> other.sort_key) * @reversed
|
53
|
+
end
|
54
|
+
|
55
|
+
# Get the packet item
|
56
|
+
def packet_item
|
57
|
+
@packet_item
|
58
|
+
end
|
59
|
+
|
60
|
+
# Pass-through method
|
61
|
+
def data
|
62
|
+
@packet_item.data
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Creates a Packet_Item with newParent as the parent list, which is allowed to be nil.
|
67
|
+
# You can also use Packet_List#add_item instead.
|
68
|
+
def initialize(newParent, icon, *content)
|
69
|
+
@content = content
|
70
|
+
@sortable = Array.new(@content.size)
|
71
|
+
@icon = icon
|
72
|
+
@data = nil
|
73
|
+
@parent = nil
|
74
|
+
@sort_key = nil
|
75
|
+
@searchable = nil
|
76
|
+
# call parent=, don't forget the self!!
|
77
|
+
self.parent = newParent
|
78
|
+
show if newParent
|
79
|
+
# update sortable
|
80
|
+
@content.each_index do |pos|
|
81
|
+
update_sortable(pos, @content[pos]) if parent
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Get the content of the given column number.
|
86
|
+
def [](column_nr)
|
87
|
+
@content[column_nr]
|
88
|
+
end
|
89
|
+
|
90
|
+
# Set new text for the given column number.
|
91
|
+
def []=(column_nr, newVal)
|
92
|
+
@content[column_nr] = newVal
|
93
|
+
return unless @parent
|
94
|
+
@item.text = @content.join("\t")
|
95
|
+
update_sortable(column_nr, newVal)
|
96
|
+
@parent.recalc
|
97
|
+
end
|
98
|
+
|
99
|
+
# Get the sortable representation of this column's content.
|
100
|
+
def sortable(pos)
|
101
|
+
@sortable[pos]
|
102
|
+
end
|
103
|
+
|
104
|
+
# update FXIconItem's sort key and reversed status
|
105
|
+
def update_sort_key
|
106
|
+
@item.sort_key = @sortable[@parent.sort_index]
|
107
|
+
@item.reversed = @parent.reversed? ? -1 : 1
|
108
|
+
end
|
109
|
+
|
110
|
+
# Get the parent list for this item.
|
111
|
+
def parent
|
112
|
+
@parent
|
113
|
+
end
|
114
|
+
|
115
|
+
# Set a new parent. This removes this item from the current list and adds itself to
|
116
|
+
# the new one.
|
117
|
+
def parent=(newParent)
|
118
|
+
return if newParent == @parent
|
119
|
+
remove_item if @parent
|
120
|
+
@parent = newParent
|
121
|
+
@content.each_index do |pos|
|
122
|
+
update_sortable(pos, @content[pos]) if @parent
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Shows item on parent without updating the search index. This can be used
|
127
|
+
# if an item is removed and added to the same list.
|
128
|
+
def show
|
129
|
+
create_item
|
130
|
+
@parent.add_item(self)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Get the wrapper item.
|
134
|
+
def fox_item
|
135
|
+
@item
|
136
|
+
end
|
137
|
+
|
138
|
+
# Allows to set user data.
|
139
|
+
def data=(data)
|
140
|
+
@data = data
|
141
|
+
end
|
142
|
+
|
143
|
+
# Get user data.
|
144
|
+
def data
|
145
|
+
@data
|
146
|
+
end
|
147
|
+
|
148
|
+
# Removes the item from its parent.
|
149
|
+
def clear
|
150
|
+
@parent = nil
|
151
|
+
end
|
152
|
+
|
153
|
+
# The icon of this item.
|
154
|
+
def icon
|
155
|
+
@icon
|
156
|
+
end
|
157
|
+
|
158
|
+
private
|
159
|
+
|
160
|
+
# Calles the sort function to update the sortable representation of column pos.
|
161
|
+
def update_sortable(pos, newVal)
|
162
|
+
sort_function = @parent.sort_function(pos)
|
163
|
+
if sort_function
|
164
|
+
@sortable[pos] = sort_function.call(newVal)
|
165
|
+
else
|
166
|
+
@sortable[pos] = newVal
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Remove item from parent
|
171
|
+
def remove_item
|
172
|
+
@parent.remove_item(self)
|
173
|
+
end
|
174
|
+
|
175
|
+
# Creates wrapper item, and sets it's data
|
176
|
+
def create_item
|
177
|
+
@item = Fox_Item.new(self, @content.join("\t"), @icon, @icon)
|
178
|
+
end
|
179
|
+
end
|