tkri 0.9.0 → 0.9.1
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/bin/tkri +15 -2
- data/lib/tkri.rb +241 -54
- metadata +7 -5
data/bin/tkri
CHANGED
@@ -1,9 +1,22 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
3
|
+
begin
|
4
|
+
# If we were installed using the Gem system:
|
5
|
+
require 'tkri'
|
6
|
+
rescue LoadError => load_error
|
7
|
+
# No, we weren't installed as a Gem. We need to make Ruby aware
|
8
|
+
# of our library folder.
|
9
|
+
lib = File.join(File.dirname(__FILE__), '..', 'lib')
|
10
|
+
$: << lib
|
11
|
+
require 'tkri'
|
12
|
+
end
|
4
13
|
|
5
14
|
app = Tkri::App.new
|
6
15
|
ARGV.each do |topic|
|
7
|
-
|
16
|
+
if topic == '--dump-rc'
|
17
|
+
Tkri::DefaultSettings.dump
|
18
|
+
else
|
19
|
+
app.go topic, true
|
20
|
+
end
|
8
21
|
end
|
9
22
|
app.run
|
data/lib/tkri.rb
CHANGED
@@ -10,28 +10,117 @@ require 'tk'
|
|
10
10
|
|
11
11
|
module Tkri
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
13
|
+
# Returns the pathname of the 'rc' file.
|
14
|
+
def self.get_rc_file_path
|
15
|
+
basename = RUBY_PLATFORM.index('mswin') ? '_tkrirc' : '.tkrirc'
|
16
|
+
if ENV['HOME']
|
17
|
+
File.join(ENV['HOME'], basename)
|
18
|
+
else
|
19
|
+
# Probably Windows with no $HOME set. Dir.pwd sucks but is there
|
20
|
+
# anything better to do? At least the "Help :: About the RC file"
|
21
|
+
# screen displays this value, so the user won't be completely clueless...
|
22
|
+
File.join(Dir.pwd, basename)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module DefaultSettings
|
27
|
+
|
28
|
+
COMMAND = {
|
29
|
+
# Each platform may use a different command. The commands are indexed by any
|
30
|
+
# substring in RUBY_PLATFORM. If none matches the platform, the '__default__' key
|
31
|
+
# is used.
|
32
|
+
'__default__' => 'qri -f ansi "%s"',
|
33
|
+
|
34
|
+
# The "2>&1" thingy tells UNIX shells to print any error messages to the standard output.
|
35
|
+
# This makes it possible to see, inside Tkri, the errors `qri' (or 'ri') happens to emmit
|
36
|
+
# (this happens seldom, due to bugs in `qri', so it's not a very critical feature).
|
37
|
+
'linux' => 'qri -f ansi "%s" 2>&1',
|
38
|
+
'darwin' => 'qri -f ansi "%s" 2>&1',
|
39
|
+
|
40
|
+
# And here's the command for MS-Windows.
|
41
|
+
# It turns out Windows' CMD.EXE too supports "2>&1". This shell is used on NT-based
|
42
|
+
# systems. (In other words, if you're using the good old Windows 98, you'll have to remove
|
43
|
+
# this "2>&1").
|
44
|
+
'mswin' => 'qri.bat -f ansi "%s" 2>&1',
|
45
|
+
}
|
46
|
+
|
47
|
+
TAGS = {
|
48
|
+
# The '__base__' attibutes are applied for every textfield and textarea.
|
49
|
+
# Set the background color and font to whatever you like.
|
50
|
+
#
|
51
|
+
# Font families are designated by an ordered array of names. The first
|
52
|
+
# found on the system will be used. So make sure to put a generic family
|
53
|
+
# name (i.e., one of: 'courier', 'times', 'helvetica') at the end to serve
|
54
|
+
# as a fallback.
|
55
|
+
'__base__' => { :background => '#ffeeff', :font => { :family => ['Bitstream Vera Sans Mono', 'courier'], :size => 10 } },
|
56
|
+
'bold' => { :foreground => 'blue' },
|
57
|
+
'italic' => { :foreground => '#6b8e23' }, # greenish
|
58
|
+
'code' => { :foreground => '#1874cd' }, # blueish
|
59
|
+
'header2' => { :background => '#ffe4b5', :font => { :family => ['helvetica'], :size => 16 } },
|
60
|
+
'header3' => { :background => '#ffe4b5', :font => { :family => ['helvetica'], :size => 16 } },
|
61
|
+
'keyword' => { :foreground => 'red' },
|
62
|
+
'search' => { :background => 'yellow' },
|
63
|
+
'hidden' => { :elide => true },
|
64
|
+
}
|
65
|
+
|
66
|
+
# Dump these settings into an 'rc' file.
|
67
|
+
def self.dump
|
68
|
+
require 'yaml'
|
69
|
+
open(Tkri.get_rc_file_path, 'w') do |f|
|
70
|
+
f.puts "#"
|
71
|
+
f.puts "# The documentation for these settings can be found in this file:"
|
72
|
+
f.puts "# " + File.expand_path(__FILE__)
|
73
|
+
f.puts "# Also, see the 'About the `rc` file' under the 'Help' menu."
|
74
|
+
f.puts "#"
|
75
|
+
f.puts "# You may erase any setting in this file for which you want to use"
|
76
|
+
f.puts "# the default value."
|
77
|
+
f.puts "#"
|
78
|
+
f.puts({ 'command' => COMMAND, 'tags' => TAGS }.to_yaml)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end # module DefaultSettings
|
83
|
+
|
84
|
+
module Settings
|
85
|
+
COMMAND = DefaultSettings::COMMAND.dup
|
86
|
+
TAGS = DefaultSettings::TAGS.dup
|
87
|
+
|
88
|
+
# Load the settings from the 'rc' file. We merge them into the existing settings.
|
89
|
+
def self.load
|
90
|
+
if File.exist? Tkri.get_rc_file_path
|
91
|
+
require 'yaml'
|
92
|
+
settings = YAML.load_file(Tkri.get_rc_file_path)
|
93
|
+
if settings.instance_of? Hash
|
94
|
+
COMMAND.merge!(settings['command']) if settings['command']
|
95
|
+
TAGS.merge!(settings['tags']) if settings['tags']
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
32
100
|
|
33
101
|
HistoryEntry = Struct.new(:topic, :cursor, :yview)
|
34
102
|
|
103
|
+
# hash_to_configuration() converts any of the TAG hashes, above, to a hash suitable
|
104
|
+
# for use in Tk. Corrently, it only converts the :font attribute to a TkFont instance.
|
105
|
+
def self.hash_to_configuration(hash)
|
106
|
+
ret = hash.dup
|
107
|
+
if ret[:font].instance_of? Hash
|
108
|
+
if ret[:font][:family]
|
109
|
+
ret[:font] = ret[:font].dup
|
110
|
+
availables = TkFont.families.map { |s| s.downcase }
|
111
|
+
# Select the first family available on this system.
|
112
|
+
Array(ret[:font][:family]).each { |family|
|
113
|
+
if availables.include? family.downcase
|
114
|
+
ret[:font][:family] = family
|
115
|
+
break
|
116
|
+
end
|
117
|
+
}
|
118
|
+
end
|
119
|
+
ret[:font] = TkFont.new(ret[:font])
|
120
|
+
end
|
121
|
+
return ret
|
122
|
+
end
|
123
|
+
|
35
124
|
# A Tab encapsulates an @address box, where you type the topic to go to; a "Go"
|
36
125
|
# button; and an @info box in which to show the topic.
|
37
126
|
class Tab < TkFrame
|
@@ -54,7 +143,8 @@ class Tab < TkFrame
|
|
54
143
|
}
|
55
144
|
}
|
56
145
|
@address = TkEntry.new(addressbar) {
|
57
|
-
configure
|
146
|
+
configure Tkri::hash_to_configuration(Settings::TAGS['__base__'])
|
147
|
+
configure :width => 30
|
58
148
|
pack :side => 'left', :expand => true, :fill => 'both'
|
59
149
|
}
|
60
150
|
|
@@ -63,6 +153,7 @@ class Tab < TkFrame
|
|
63
153
|
#
|
64
154
|
_frame = self
|
65
155
|
@info = TkText.new(self) { |t|
|
156
|
+
configure Tkri::hash_to_configuration(Settings::TAGS['__base__'])
|
66
157
|
pack :side => 'left', :fill => 'both', :expand => true
|
67
158
|
TkScrollbar.new(_frame) { |s|
|
68
159
|
pack :side => 'right', :fill => 'y'
|
@@ -71,7 +162,7 @@ class Tab < TkFrame
|
|
71
162
|
}
|
72
163
|
}
|
73
164
|
|
74
|
-
TAGS.each do |name, conf|
|
165
|
+
Settings::TAGS.each do |name, conf|
|
75
166
|
@info.tag_configure(name, conf)
|
76
167
|
end
|
77
168
|
|
@@ -82,6 +173,8 @@ class Tab < TkFrame
|
|
82
173
|
# If I make the following "ButtonRelease-2" instead, the <PasteSelection>
|
83
174
|
# cancellation that follows won't work. Strange.
|
84
175
|
@info.bind('Button-2') { |e| go_xy_word(e.x, e.y, true) }
|
176
|
+
@info.bind('Key-Return') { go_caret_word(); break }
|
177
|
+
@info.bind('Key-KP_Enter') { go_caret_word(); break }
|
85
178
|
@info.bind('ButtonRelease-3') { |e| back }
|
86
179
|
@info.bind('Key-BackSpace') { |e| back; break }
|
87
180
|
|
@@ -165,7 +258,16 @@ class Tab < TkFrame
|
|
165
258
|
# upon releasing the mouse button.)
|
166
259
|
return
|
167
260
|
end
|
168
|
-
|
261
|
+
go_word('@' + x.to_s + ',' + y.to_s, newtab)
|
262
|
+
end
|
263
|
+
|
264
|
+
# Navigate to the topic mentioned under the caret.
|
265
|
+
def go_caret_word(newtab=false)
|
266
|
+
go_word('insert', newtab)
|
267
|
+
end
|
268
|
+
|
269
|
+
def go_word(position, newtab=false)
|
270
|
+
if (word = get_word(position))
|
169
271
|
@app.go word, newtab
|
170
272
|
end
|
171
273
|
end
|
@@ -184,15 +286,22 @@ class Tab < TkFrame
|
|
184
286
|
return ret[0].empty? ? nil : ret[2]
|
185
287
|
end
|
186
288
|
|
187
|
-
# Get the "topic"
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
289
|
+
# Get the "topic" at a certain postion.
|
290
|
+
#
|
291
|
+
# The 'position' paramter is an expression that can be, e.g., "insert"
|
292
|
+
# for the current caret position; or "@x,y" for the mouse poisition.
|
293
|
+
def get_word(position)
|
294
|
+
line = @info.get(position + ' linestart', position + ' lineend')
|
295
|
+
pos = @info.get(position + ' linestart', position).length
|
192
296
|
|
193
297
|
line = ' ' + line + ' '
|
194
298
|
pos += 1
|
195
299
|
|
300
|
+
if line[pos,1] == ' '
|
301
|
+
# If the user clicks a space between words, or after end of line, abort.
|
302
|
+
return nil
|
303
|
+
end
|
304
|
+
|
196
305
|
a = pos
|
197
306
|
a -= 1 while line[a-1,1] !~ /[ (]/
|
198
307
|
z = pos
|
@@ -209,20 +318,20 @@ class Tab < TkFrame
|
|
209
318
|
end
|
210
319
|
|
211
320
|
a -= 1 # Undo the `line = ' ' + line` we did previously.
|
212
|
-
@info.tag_add('keyword', '%s linestart + %d chars' % [
|
213
|
-
'%s linestart + %d chars' % [
|
321
|
+
@info.tag_add('keyword', '%s linestart + %d chars' % [ position, a ],
|
322
|
+
'%s linestart + %d chars' % [ position, a+word.length ])
|
214
323
|
word.strip!
|
215
324
|
|
216
325
|
return nil if word.empty?
|
217
326
|
return nil if word =~ /^-+$/ # A special case: a line of '-----'
|
218
327
|
|
219
|
-
case get_previous_header(
|
328
|
+
case get_previous_header(position)
|
220
329
|
when 'Instance methods:'
|
221
330
|
word = topic + '#' + word
|
222
331
|
when 'Class methods:'
|
223
332
|
word = topic + '::' + word
|
224
333
|
when 'Includes:'
|
225
|
-
word = get_previous_class(
|
334
|
+
word = get_previous_class(position) + '#' + word if not word =~ /^[A-Z]/
|
226
335
|
end
|
227
336
|
|
228
337
|
return word
|
@@ -429,6 +538,8 @@ class App
|
|
429
538
|
def initialize
|
430
539
|
@root = root = TkRoot.new { title 'Tkri' }
|
431
540
|
@search_word = nil
|
541
|
+
|
542
|
+
Settings.load
|
432
543
|
|
433
544
|
menu_spec = [
|
434
545
|
[['File', 0],
|
@@ -442,8 +553,10 @@ class App
|
|
442
553
|
# The following :menu_name=>'help' has no effect, but it should have...
|
443
554
|
# probably a bug in RubyTK.
|
444
555
|
[['Help', 0, { :menu_name => 'help' }],
|
445
|
-
['
|
446
|
-
['Key bindings', proc { help_key_bindings }, 0]
|
556
|
+
['Overview', proc { help_overview }, 0],
|
557
|
+
['Key bindings', proc { help_key_bindings }, 0],
|
558
|
+
['Tips and tricks', proc { help_tips_and_tricks }, 0],
|
559
|
+
['About the $HOME/.tkrirc file', proc { help_rc }, 0]],
|
447
560
|
]
|
448
561
|
TkMenubar.new(root, menu_spec).pack(:side => 'top', :fill => 'x')
|
449
562
|
|
@@ -507,12 +620,14 @@ class App
|
|
507
620
|
def search
|
508
621
|
self.status = 'Type the string to search'
|
509
622
|
entry = TkEntry.new(@root).pack(:fill => 'x').focus
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
623
|
+
['Key-Return', 'Key-KP_Enter'].each do |event|
|
624
|
+
entry.bind(event) {
|
625
|
+
self.status = ''
|
626
|
+
@search_word = entry.get
|
627
|
+
@tabs.current.search_next_word entry.get
|
628
|
+
entry.destroy
|
629
|
+
}
|
630
|
+
end
|
516
631
|
['Key-Escape', 'FocusOut'].each do |event|
|
517
632
|
entry.bind(event) {
|
518
633
|
self.status = ''
|
@@ -533,41 +648,62 @@ class App
|
|
533
648
|
|
534
649
|
return @ri_cache[topic] if @ri_cache[topic]
|
535
650
|
|
536
|
-
command = COMMAND.select { |k,v| RUBY_PLATFORM.index(k) }.first.to_a[1] || COMMAND['
|
537
|
-
|
651
|
+
command = Settings::COMMAND.select { |k,v| RUBY_PLATFORM.index(k) }.first.to_a[1] || Settings::COMMAND['__default__']
|
652
|
+
text = Kernel.`(command % topic) # `
|
538
653
|
if $? != 0
|
539
|
-
|
654
|
+
text += "\n" + "ERROR: Failed to run the command '%s' (exit code: %d). Please make sure you have this command in your PATH.\n\nYou may wish to modify this program's source (%s) to update the command to something that works on your system." % [command % topic, $?, $0]
|
540
655
|
else
|
541
|
-
if
|
542
|
-
|
656
|
+
if text == "nil\n"
|
657
|
+
text = 'Topic "%s" not found.' % topic
|
543
658
|
end
|
544
|
-
@ri_cache[topic] =
|
659
|
+
@ri_cache[topic] = text
|
545
660
|
@cached_topics << topic
|
546
661
|
end
|
547
662
|
|
663
|
+
# Make the "Multiple choices" output easier to read.
|
664
|
+
if text.match /Multiple choices/
|
665
|
+
text.gsub! /,\s+/, "\n"
|
666
|
+
text.gsub! /^ */, ""
|
667
|
+
text.gsub! /\n/, "\n "
|
668
|
+
end
|
669
|
+
|
548
670
|
# Remove the oldest topic from the cache
|
549
|
-
if @cached_topics.length >
|
671
|
+
if @cached_topics.length > 20
|
550
672
|
@ri_cache.delete @cached_topics.shift
|
551
673
|
end
|
552
674
|
|
553
|
-
return
|
675
|
+
return text
|
554
676
|
end
|
555
677
|
|
556
678
|
def helpbox(title, text)
|
557
679
|
w = TkToplevel.new(:title => title)
|
558
|
-
TkText.new(w, :height => text.count("\n"), :width => 80).pack.insert('1.0', text)
|
680
|
+
t = TkText.new(w, :height => text.count("\n"), :width => 80).pack.insert('1.0', text)
|
681
|
+
t.configure Tkri::hash_to_configuration(Settings::TAGS['__base__'])
|
559
682
|
TkButton.new(w, :text => 'Close', :command => proc { w.destroy }).pack
|
560
683
|
end
|
561
|
-
|
562
|
-
def
|
563
|
-
helpbox('Help:
|
564
|
-
|
565
|
-
|
684
|
+
|
685
|
+
def help_overview
|
686
|
+
helpbox('Help: Overview', <<EOS)
|
687
|
+
ABOUT
|
688
|
+
|
689
|
+
Tkri (pronounce TIK-ri) is a GUI front-end to the 'ri', or
|
690
|
+
'qri', executables. By default it uses 'qri', which is part
|
691
|
+
of the Fast-RI package.
|
692
|
+
|
693
|
+
Tkri displays the output of that program in a window where
|
694
|
+
each work is "hyperlinked".
|
695
|
+
|
696
|
+
USAGE
|
697
|
+
|
698
|
+
Launch tkri by typing 'tkri' at the operating system prompt. You
|
699
|
+
can provide a starting topic as an argument on the command line.
|
700
|
+
Inside the application, type the topic you wish to go to at the
|
701
|
+
address bar, or click on a word in the main text.
|
566
702
|
EOS
|
567
703
|
end
|
568
704
|
|
569
705
|
def help_key_bindings
|
570
|
-
helpbox('Help:
|
706
|
+
helpbox('Help: Key bindings', <<EOS)
|
571
707
|
Left mouse button
|
572
708
|
Navigate to the topic under the cursor.
|
573
709
|
Middle mouse button
|
@@ -578,6 +714,57 @@ Ctrl+W. Or right mouse button, on a tab button
|
|
578
714
|
Close the tab (unless this is the only tab).
|
579
715
|
Ctrl+L
|
580
716
|
Move the keyboard focus to the "address" box, where you can type a topic.
|
717
|
+
/
|
718
|
+
Find string in page.
|
719
|
+
EOS
|
720
|
+
end
|
721
|
+
|
722
|
+
def help_tips_and_tricks
|
723
|
+
helpbox('Help: Tips and tricks', <<EOS)
|
724
|
+
Some random tips:
|
725
|
+
|
726
|
+
Type '/' to quickly highlight a string in the page. (If the
|
727
|
+
string happens to be off-screen, hit ENTER to jump to it.)
|
728
|
+
|
729
|
+
Ctrl+L is probably the fastest way to move the keyboard
|
730
|
+
focus to the "address box".
|
731
|
+
|
732
|
+
The references for "Hash", "Array" and "String" are the most
|
733
|
+
sought-after, so instead of typing their full name in the address
|
734
|
+
box you can just type the letters h, a or s, respectively.
|
735
|
+
|
736
|
+
You can type the topic(s) directly on the command line;
|
737
|
+
e.g., "tkri Array.flatten sort_by"
|
738
|
+
|
739
|
+
Left-clicking on a word doesn't yet send you to a new page. It's
|
740
|
+
*releasing* the button that sends you there. This makes it possible to
|
741
|
+
select pieces of code: left-click, then drag, then release; since some
|
742
|
+
text is now selected, Tkri figures out that's all you wanted.
|
743
|
+
EOS
|
744
|
+
end
|
745
|
+
|
746
|
+
def help_rc
|
747
|
+
helpbox('Help: RC', <<EOS)
|
748
|
+
Tkri has some settings. E.g., the colors and fonts it uses.
|
749
|
+
|
750
|
+
These settings are hard-coded in the source code. But you can
|
751
|
+
override them by having an 'rc' file in your home folder. On
|
752
|
+
your system this file is here:
|
753
|
+
|
754
|
+
#{Tkri.get_rc_file_path}
|
755
|
+
|
756
|
+
(If it's at a weird place, set your $HOME environment variable.)
|
757
|
+
|
758
|
+
Of course, you're a busy person and don't have time to write
|
759
|
+
this file from scratch. So you're going to tell Tkri to write
|
760
|
+
this file for you; When you type:
|
761
|
+
|
762
|
+
tkri --dump-rc
|
763
|
+
|
764
|
+
you're telling Tkri to dump all its default settings into that
|
765
|
+
file. Then edit this file to your liking using your text editor.
|
766
|
+
Finally, run tkri; it will automatically merge the settings from
|
767
|
+
this file onto the hard-coded ones.
|
581
768
|
EOS
|
582
769
|
end
|
583
770
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tkri
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mooffie
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-10-26 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -34,8 +34,10 @@ files:
|
|
34
34
|
- README
|
35
35
|
- lib/tkri.rb
|
36
36
|
- bin/tkri
|
37
|
-
has_rdoc:
|
37
|
+
has_rdoc: true
|
38
38
|
homepage: http://rubyforge.org/projects/tkri/
|
39
|
+
licenses: []
|
40
|
+
|
39
41
|
post_install_message:
|
40
42
|
rdoc_options: []
|
41
43
|
|
@@ -56,9 +58,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
56
58
|
requirements: []
|
57
59
|
|
58
60
|
rubyforge_project: tkri
|
59
|
-
rubygems_version: 1.3.
|
61
|
+
rubygems_version: 1.3.3
|
60
62
|
signing_key:
|
61
|
-
specification_version:
|
63
|
+
specification_version: 3
|
62
64
|
summary: GUI front-end to FastRI's or RI's executables.
|
63
65
|
test_files: []
|
64
66
|
|