tkri 0.9.0 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|