tkri 0.9.2 → 0.9.3
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/README +2 -0
- data/lib/tkri.rb +285 -73
- metadata +2 -2
data/README
CHANGED
@@ -9,3 +9,5 @@ Launch it by typing 'tkri' at the operating system prompt. You can
|
|
9
9
|
provide a starting topic as an argument on the command line. Inside the
|
10
10
|
application, type the topic you wish to go to at the address bar, or
|
11
11
|
click on a word in the main text.
|
12
|
+
|
13
|
+
See the Help menu for more details.
|
data/lib/tkri.rb
CHANGED
@@ -52,17 +52,84 @@ module Tkri
|
|
52
52
|
# found on the system will be used. So make sure to put a generic family
|
53
53
|
# name (i.e., one of: 'courier', 'times', 'helvetica') at the end to serve
|
54
54
|
# as a fallback.
|
55
|
-
'__base__' => { :background => '#ffeeff', :font => { :family => ['Bitstream Vera Sans Mono', '
|
55
|
+
'__base__' => { :background => '#ffeeff', :font => { :family => ['Bitstream Vera Sans Mono', 'Menlo', 'Monaco', 'Courier'], :size => 10 } },
|
56
56
|
'bold' => { :foreground => 'blue' },
|
57
57
|
'italic' => { :foreground => '#6b8e23' }, # greenish
|
58
58
|
'code' => { :foreground => '#1874cd' }, # blueish
|
59
|
-
'header2' => { :background => '#ffe4b5', :font => { :family => ['
|
60
|
-
'header3' => { :background => '#ffe4b5', :font => { :family => ['
|
59
|
+
'header2' => { :background => '#ffe4b5', :font => { :family => ['Geneva', 'Arial', 'Helvetica'], :size => 12 } },
|
60
|
+
'header3' => { :background => '#ffe4b5', :font => { :family => ['Geneva', 'Arial', 'Helvetica'], :size => 14 } },
|
61
61
|
'keyword' => { :foreground => 'red' },
|
62
62
|
'search' => { :background => 'yellow' },
|
63
63
|
'hidden' => { :elide => true },
|
64
64
|
}
|
65
|
-
|
65
|
+
|
66
|
+
BINDINGS = {
|
67
|
+
# The keys (e.g. 'b1001') in this hash are named arbitrarily and are completely
|
68
|
+
# ignored by Tkri. They exist only to enable you to override certain bindings in
|
69
|
+
# your 'rc' file. I'm not going to rename keys, only to add to them (as new
|
70
|
+
# bindings are added to newer versions), so you won't have to update your 'rc'
|
71
|
+
# file whenever you update Tkri.
|
72
|
+
|
73
|
+
# For the :key syntax, see the Tk manual. The :source is the widget to attach the
|
74
|
+
# binding to. The :commands are methods to execute; they're conveniently prefixed
|
75
|
+
# by 'interactive_' to enable you to easily locate all of them in the source code.
|
76
|
+
|
77
|
+
'b1001' => { :key => 'Control-q', :source => 'root', :command => 'interactive_quit' },
|
78
|
+
'b1002' => { :key => 'Control-t', :source => 'root', :command => 'interactive_new_tab' },
|
79
|
+
'b1003' => { :key => 'Control-w', :source => 'root', :command => 'interactive_close_tab' },
|
80
|
+
'b1004' => { :key => 'Control-l', :source => 'root', :command => 'interactive_focus_address' },
|
81
|
+
|
82
|
+
# Note: tabs indexes are zero-based.
|
83
|
+
'b2001' => { :key => 'Alt-Key-1', :source => 'root', :command => 'interactive_switch_to_tab_0' },
|
84
|
+
'b2002' => { :key => 'Alt-Key-2', :source => 'root', :command => 'interactive_switch_to_tab_1' },
|
85
|
+
'b2003' => { :key => 'Alt-Key-3', :source => 'root', :command => 'interactive_switch_to_tab_2' },
|
86
|
+
'b2004' => { :key => 'Alt-Key-4', :source => 'root', :command => 'interactive_switch_to_tab_3' },
|
87
|
+
'b2005' => { :key => 'Alt-Key-5', :source => 'root', :command => 'interactive_switch_to_tab_4' },
|
88
|
+
'b2006' => { :key => 'Alt-Key-6', :source => 'root', :command => 'interactive_switch_to_tab_5' },
|
89
|
+
'b2007' => { :key => 'Alt-Key-7', :source => 'root', :command => 'interactive_switch_to_tab_6' },
|
90
|
+
'b2008' => { :key => 'Alt-Key-8', :source => 'root', :command => 'interactive_switch_to_tab_7' },
|
91
|
+
'b2009' => { :key => 'Alt-Key-9', :source => 'root', :command => 'interactive_switch_to_tab_8' },
|
92
|
+
'b2010' => { :key => 'Alt-Key-0', :source => 'root', :command => 'interactive_switch_to_tab_9' },
|
93
|
+
|
94
|
+
# For the following we don't use interactive_close_tab because we want to close the
|
95
|
+
# tab associated with the button, not the current tab.
|
96
|
+
'b1007' => { :key => 'Button-2', :source => 'tabbutton', :command => 'interactive_close_button_tab' },
|
97
|
+
|
98
|
+
# 'Prior' and 'Next' are page up and page down, respectively.
|
99
|
+
'b1005' => { :key => 'Control-Key-Prior', :source => 'root', :command => 'interactive_switch_to_prev_tab' },
|
100
|
+
'b1006' => { :key => 'Control-Key-Next', :source => 'root', :command => 'interactive_switch_to_next_tab' },
|
101
|
+
|
102
|
+
'b1008' => { :key => 'ButtonRelease-1', :source => 'info', :command => 'interactive_goto_topic_under_mouse' },
|
103
|
+
'b1008b' => { :key => 'Control-Button-1', :source => 'info', :command => 'interactive_goto_topic_under_caret_or_selected', :cancel_default => true },
|
104
|
+
'b1011' => { :key => 'Key-Return', :source => 'info', :command => 'interactive_goto_topic_under_caret_or_selected', :cancel_default => true },
|
105
|
+
'b1012' => { :key => 'Key-Return', :source => 'addressbox', :command => 'interactive_goto_topic_in_addressbox' },
|
106
|
+
# If I make the following "ButtonRelease-2" instead, the <PasteSelection>
|
107
|
+
# cancellation that follows won't work. Strange.
|
108
|
+
'b1009' => { :key => 'Button-2', :source => 'info', :command => 'interactive_goto_topic_under_mouse_in_new_tab', :cancel_default => true },
|
109
|
+
# Under X11, Button-2 is also used to paste the selection. So we disable pasting. All
|
110
|
+
# because Tk doesn't support read-only text widgets.
|
111
|
+
'b1010' => { :key => '<PasteSelection>', :source => 'info', :cancel_default => true },
|
112
|
+
|
113
|
+
# History.
|
114
|
+
'b1013' => { :key => 'ButtonRelease-3', :source => 'info', :command => 'interactive_history_back' },
|
115
|
+
'b1014' => { :key => 'Key-BackSpace', :source => 'info', :command => 'interactive_history_back', :cancel_default => true },
|
116
|
+
|
117
|
+
# Tk doesn't support read-only rext widgets. So for every "ascii" global binding we also
|
118
|
+
# need to duplicate it on the 'info' widget, :cancel_default'ing it.
|
119
|
+
#
|
120
|
+
# "Global" bindings are those attached to the 'root' window. For "ascii" bindings make sure
|
121
|
+
# to turn on :when_not_tkentry, or else these events will fire up when the key is pressed in
|
122
|
+
# the addressbox too (which is a widget of type TkEntry).
|
123
|
+
'b1015' => { :key => 'Key-slash', :source => 'root', :command => 'interactive_initiate_search', :when_not_tkentry => true },
|
124
|
+
'b1016' => { :key => 'Key-n', :source => 'root', :command => 'interactive_search_next', :when_not_tkentry => true },
|
125
|
+
'b1017' => { :key => 'Key-N', :source => 'root', :command => 'interactive_search_prev', :when_not_tkentry => true },
|
126
|
+
'b1018' => { :key => 'Key-u', :source => 'root', :command => 'interactive_go_up', :when_not_tkentry => true },
|
127
|
+
'b1019' => { :key => 'Key-slash', :source => 'info', :command => 'interactive_initiate_search', :cancel_default => true },
|
128
|
+
'b1020' => { :key => 'Key-n', :source => 'info', :command => 'interactive_search_next', :cancel_default => true },
|
129
|
+
'b1021' => { :key => 'Key-N', :source => 'info', :command => 'interactive_search_prev', :cancel_default => true },
|
130
|
+
'b1022' => { :key => 'Key-u', :source => 'info', :command => 'interactive_go_up', :cancel_default => true },
|
131
|
+
}
|
132
|
+
|
66
133
|
# Dump these settings into an 'rc' file.
|
67
134
|
def self.dump
|
68
135
|
require 'yaml'
|
@@ -75,15 +142,20 @@ module Tkri
|
|
75
142
|
f.puts "# You may erase any setting in this file for which you want to use"
|
76
143
|
f.puts "# the default value."
|
77
144
|
f.puts "#"
|
78
|
-
f.puts({ 'command' => COMMAND, 'tags' => TAGS }.to_yaml)
|
145
|
+
f.puts({ 'command' => COMMAND, 'tags' => TAGS, 'bindings' => BINDINGS }.to_yaml)
|
79
146
|
end
|
80
147
|
end
|
81
148
|
|
82
149
|
end # module DefaultSettings
|
83
150
|
|
151
|
+
class << self
|
152
|
+
attr_accessor :the_application
|
153
|
+
end
|
154
|
+
|
84
155
|
module Settings
|
85
156
|
COMMAND = DefaultSettings::COMMAND.dup
|
86
157
|
TAGS = DefaultSettings::TAGS.dup
|
158
|
+
BINDINGS = DefaultSettings::BINDINGS
|
87
159
|
|
88
160
|
# Load the settings from the 'rc' file. We merge them into the existing settings.
|
89
161
|
def self.load
|
@@ -93,6 +165,7 @@ module Tkri
|
|
93
165
|
if settings.instance_of? Hash
|
94
166
|
COMMAND.merge!(settings['command']) if settings['command']
|
95
167
|
TAGS.merge!(settings['tags']) if settings['tags']
|
168
|
+
BINDINGS.merge!(settings['bindings']) if settings['bindings']
|
96
169
|
end
|
97
170
|
end
|
98
171
|
end
|
@@ -117,6 +190,29 @@ def self.hash_to_configuration(hash)
|
|
117
190
|
return ret
|
118
191
|
end
|
119
192
|
|
193
|
+
# Attachs Settings::BINDINGS to a certain widget.
|
194
|
+
def self.attach_bindings(widget, widget_id_string)
|
195
|
+
Tkri::Settings::BINDINGS.each_pair { |ignored_key, b|
|
196
|
+
if (b[:source] == widget_id_string)
|
197
|
+
keys = Array(b[:key])
|
198
|
+
if b[:key] == 'Key-Return'
|
199
|
+
keys.push 'Key-KP_Enter'
|
200
|
+
end
|
201
|
+
keys.each { |key|
|
202
|
+
widget.bind(key) { |event|
|
203
|
+
skip = (b[:when_not_tkentry] and event.widget.class == TkEntry)
|
204
|
+
if !skip
|
205
|
+
if b[:command] # Sometimes we're only interested in :cancel_default.
|
206
|
+
Tkri.the_application.invoke_command(b[:command], event)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
break if b[:cancel_default]
|
210
|
+
}
|
211
|
+
}
|
212
|
+
end
|
213
|
+
}
|
214
|
+
end
|
215
|
+
|
120
216
|
# A Tab encapsulates an @address box, where you type the topic to go to; a "Go"
|
121
217
|
# button; and an @info box in which to show the topic.
|
122
218
|
class Tab < TkFrame
|
@@ -162,29 +258,46 @@ class Tab < TkFrame
|
|
162
258
|
@info.tag_configure(name, Tkri::hash_to_configuration(hash))
|
163
259
|
end
|
164
260
|
|
165
|
-
|
166
|
-
@
|
167
|
-
@address.bind('Key-KP_Enter') { go }
|
168
|
-
@info.bind('ButtonRelease-1') { |e| go_xy_word(e.x, e.y) }
|
169
|
-
# If I make the following "ButtonRelease-2" instead, the <PasteSelection>
|
170
|
-
# cancellation that follows won't work. Strange.
|
171
|
-
@info.bind('Button-2') { |e| go_xy_word(e.x, e.y, true) }
|
172
|
-
@info.bind('Key-Return') { go_caret_word(); break }
|
173
|
-
@info.bind('Key-KP_Enter') { go_caret_word(); break }
|
174
|
-
@info.bind('ButtonRelease-3') { |e| back }
|
175
|
-
@info.bind('Key-BackSpace') { |e| back; break }
|
176
|
-
|
177
|
-
# Tk doesn't support "read-only" text widget. We "disable" the following
|
178
|
-
# keys explicitly (using 'break'). We also forward these search keys to
|
179
|
-
# @app.
|
180
|
-
@info.bind('<PasteSelection>') { break }
|
181
|
-
@info.bind('Key-slash') { @app.search; break }
|
182
|
-
@info.bind('Key-n') { @app.search_next; break }
|
183
|
-
@info.bind('Key-N') { @app.search_prev; break }
|
261
|
+
Tkri.attach_bindings @address, 'addressbox'
|
262
|
+
Tkri.attach_bindings @info, 'info'
|
184
263
|
|
185
264
|
@history = []
|
186
265
|
end
|
187
266
|
|
267
|
+
def interactive_history_back e
|
268
|
+
back
|
269
|
+
end
|
270
|
+
|
271
|
+
def interactive_goto_topic_in_addressbox e
|
272
|
+
go
|
273
|
+
end
|
274
|
+
|
275
|
+
def interactive_goto_topic_under_mouse e
|
276
|
+
go_xy_word(e.x, e.y)
|
277
|
+
end
|
278
|
+
|
279
|
+
def interactive_goto_topic_under_mouse_in_new_tab e
|
280
|
+
go_xy_word(e.x, e.y, true)
|
281
|
+
end
|
282
|
+
|
283
|
+
def interactive_goto_topic_under_caret_or_selected e
|
284
|
+
if get_selection.length > 0
|
285
|
+
go get_selection
|
286
|
+
else
|
287
|
+
go_caret_word()
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
# It seeks RubyTk doesn't support the the getSelected method for Text widgets.
|
292
|
+
# So here's a method of our own to get the selection.
|
293
|
+
def get_selection
|
294
|
+
begin
|
295
|
+
@info.get('sel.first', 'sel.last')
|
296
|
+
rescue
|
297
|
+
''
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
188
301
|
# Moves the keyboard focus to the address box. Also, selects all the
|
189
302
|
# text, like modern GUIs do.
|
190
303
|
def focus_address
|
@@ -193,6 +306,10 @@ class Tab < TkFrame
|
|
193
306
|
@address.focus
|
194
307
|
end
|
195
308
|
|
309
|
+
def interactive_focus_address e
|
310
|
+
focus_address
|
311
|
+
end
|
312
|
+
|
196
313
|
# Finds the next occurrence of a word.
|
197
314
|
def search_next_word(word)
|
198
315
|
@info.focus
|
@@ -245,6 +362,13 @@ class Tab < TkFrame
|
|
245
362
|
end
|
246
363
|
end
|
247
364
|
|
365
|
+
# Go "up". That is, if we're browsing a method, go to the class.
|
366
|
+
def interactive_go_up e
|
367
|
+
if topic and topic =~ /(.*)(::|#|\.)/
|
368
|
+
@app.go $1
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
248
372
|
# Navigate to the topic mentioned under the mouse cursor (given by x,y
|
249
373
|
# coordinates)
|
250
374
|
def go_xy_word(x, y, newtab=false)
|
@@ -450,29 +574,32 @@ class Tabsbar < TkFrame
|
|
450
574
|
build_buttons
|
451
575
|
end
|
452
576
|
|
453
|
-
def
|
577
|
+
def set_current_tab_by_index new
|
454
578
|
@buttons.each_with_index do |b, i|
|
455
579
|
b.relief = (i == new) ? 'sunken' : 'raised'
|
456
580
|
end
|
457
|
-
@tabs.
|
581
|
+
@tabs.set_current_tab_by_index new
|
458
582
|
end
|
459
583
|
|
460
584
|
def build_buttons
|
461
585
|
@buttons.each { |b| b.destroy }
|
462
586
|
@buttons = []
|
463
|
-
|
464
587
|
@tabs.each_with_index do |tab, i|
|
465
588
|
b = TkButton.new(self, :text => (tab.topic || '<new>')).pack :side => 'left'
|
466
|
-
b.command {
|
467
|
-
b
|
589
|
+
b.command { set_current_tab_by_index i }
|
590
|
+
Tkri.attach_bindings b, 'tabbutton'
|
468
591
|
@buttons << b
|
469
592
|
end
|
470
|
-
|
471
593
|
plus = TkButton.new(self, :text => '+').pack :side => 'left'
|
472
594
|
plus.command { @tabs.new_tab }
|
473
595
|
@buttons << plus
|
596
|
+
set_current_tab_by_index @tabs.current_tab_as_index
|
597
|
+
end
|
474
598
|
|
475
|
-
|
599
|
+
def interactive_close_button_tab e
|
600
|
+
if idx = @buttons.index(e.widget)
|
601
|
+
@tabs.close @tabs.get(idx)
|
602
|
+
end
|
476
603
|
end
|
477
604
|
end
|
478
605
|
|
@@ -493,32 +620,80 @@ class Tabs < TkFrame
|
|
493
620
|
tab = Tab.new(self, @app)
|
494
621
|
tab.focus_address
|
495
622
|
@tabs << tab
|
496
|
-
|
497
|
-
@app.refresh_tabsbar
|
623
|
+
set_current_tab_by_index(@tabs.size - 1, true)
|
624
|
+
# @app.refresh_tabsbar
|
625
|
+
end
|
626
|
+
|
627
|
+
def interactive_new_tab e
|
628
|
+
new_tab
|
629
|
+
end
|
630
|
+
|
631
|
+
def get(i)
|
632
|
+
@tabs[i]
|
498
633
|
end
|
499
634
|
|
500
635
|
def close(tab)
|
501
636
|
if (@tabs.size > 1 and i = @tabs.index(tab))
|
502
637
|
@tabs.delete_at i
|
503
638
|
tab.destroy
|
504
|
-
|
639
|
+
set_current_tab_by_index(@current - 1) if @current >= i and @current > 0
|
505
640
|
@app.refresh_tabsbar
|
506
641
|
end
|
507
642
|
end
|
508
643
|
|
509
|
-
def
|
510
|
-
|
511
|
-
|
644
|
+
def set_current_tab_by_index(tab_index, refresh=false)
|
645
|
+
if tab_index < @tabs.size
|
646
|
+
self.each_with_index do |tab, i|
|
647
|
+
if i == tab_index;
|
648
|
+
tab.show
|
649
|
+
# Unless we focus on the new tab, the focus may stay at the old tab's address box.
|
650
|
+
tab.focus
|
651
|
+
else
|
652
|
+
tab.hide
|
653
|
+
end
|
654
|
+
end
|
655
|
+
@current = tab_index
|
512
656
|
end
|
513
|
-
@
|
657
|
+
@app.refresh_tabsbar if refresh
|
514
658
|
end
|
515
659
|
|
516
|
-
def
|
660
|
+
def switch_to(tab_index)
|
661
|
+
set_current_tab_by_index(tab_index, true)
|
662
|
+
end
|
663
|
+
|
664
|
+
def interactive_switch_to_tab_0 e; switch_to 0; end
|
665
|
+
def interactive_switch_to_tab_1 e; switch_to 1; end
|
666
|
+
def interactive_switch_to_tab_2 e; switch_to 2; end
|
667
|
+
def interactive_switch_to_tab_3 e; switch_to 3; end
|
668
|
+
def interactive_switch_to_tab_4 e; switch_to 4; end
|
669
|
+
def interactive_switch_to_tab_5 e; switch_to 5; end
|
670
|
+
def interactive_switch_to_tab_6 e; switch_to 6; end
|
671
|
+
def interactive_switch_to_tab_7 e; switch_to 7; end
|
672
|
+
def interactive_switch_to_tab_8 e; switch_to 8; end
|
673
|
+
def interactive_switch_to_tab_9 e; switch_to 9; end
|
674
|
+
|
675
|
+
def interactive_switch_to_prev_tab e
|
676
|
+
new = current_tab_as_index - 1
|
677
|
+
new = @tabs.size - 1 if new < 0
|
678
|
+
set_current_tab_by_index(new, true)
|
679
|
+
end
|
680
|
+
|
681
|
+
def interactive_switch_to_next_tab e
|
682
|
+
new = current_tab_as_index + 1
|
683
|
+
new = 0 if new >= @tabs.size
|
684
|
+
set_current_tab_by_index(new, true)
|
685
|
+
end
|
686
|
+
|
687
|
+
def current_tab_as_index
|
517
688
|
return @current
|
518
689
|
end
|
519
690
|
|
520
|
-
def
|
521
|
-
@tabs[
|
691
|
+
def current_tab
|
692
|
+
@tabs[current_tab_as_index]
|
693
|
+
end
|
694
|
+
|
695
|
+
def interactive_close_tab e
|
696
|
+
close current_tab
|
522
697
|
end
|
523
698
|
|
524
699
|
def each
|
@@ -531,21 +706,25 @@ end
|
|
531
706
|
|
532
707
|
class App
|
533
708
|
|
709
|
+
|
534
710
|
def initialize
|
535
711
|
@root = root = TkRoot.new { title 'Tkri' }
|
536
712
|
@search_word = nil
|
537
713
|
|
714
|
+
Tkri.the_application = self
|
715
|
+
|
538
716
|
Settings.load
|
539
717
|
|
540
718
|
menu_spec = [
|
541
719
|
[['File', 0],
|
542
|
-
['
|
720
|
+
['New tab', proc { execute 'interactive_new_tab' }, 0, 'Ctrl+T' ],
|
721
|
+
['Close tab', proc { execute 'interactive_close_tab' }, 0, 'Ctrl+W' ],
|
543
722
|
'---',
|
544
|
-
['Quit', proc {
|
723
|
+
['Quit', proc { execute 'interactive_quit' }, 0, 'Ctrl+Q' ]],
|
545
724
|
[['Search', 0],
|
546
|
-
['Search', proc {
|
547
|
-
['Repeat search', proc {
|
548
|
-
['Repeat backwards', proc {
|
725
|
+
['Search', proc { execute 'interactive_initiate_search' }, 0, '/'],
|
726
|
+
['Repeat search', proc { execute 'interactive_search_next' }, 0, 'n'],
|
727
|
+
['Repeat backwards', proc { execute 'interactive_search_prev' }, 7, 'N']],
|
549
728
|
# The following :menu_name=>'help' has no effect, but it should have...
|
550
729
|
# probably a bug in RubyTK.
|
551
730
|
[['Help', 0, { :menu_name => 'help' }],
|
@@ -557,19 +736,6 @@ class App
|
|
557
736
|
]
|
558
737
|
TkMenubar.new(root, menu_spec).pack(:side => 'top', :fill => 'x')
|
559
738
|
|
560
|
-
root.bind('Control-q') { exit }
|
561
|
-
root.bind('Control-w') { @tabs.close @tabs.current }
|
562
|
-
root.bind('Control-l') { @tabs.current.focus_address }
|
563
|
-
|
564
|
-
{ 'Key-slash' => 'search',
|
565
|
-
'Key-n' => 'search_next',
|
566
|
-
'Key-N' => 'search_prev',
|
567
|
-
}.each do |event, method|
|
568
|
-
root.bind(event) { |e|
|
569
|
-
send(method) if e.widget.class != TkEntry
|
570
|
-
}
|
571
|
-
end
|
572
|
-
|
573
739
|
@tabs = Tabs.new(root, self) {
|
574
740
|
pack :side => 'top', :fill => 'both', :expand => true
|
575
741
|
}
|
@@ -579,6 +745,31 @@ class App
|
|
579
745
|
@statusbar = TkLabel.new(root, :anchor => 'w') {
|
580
746
|
pack :side => 'bottom', :fill => 'x'
|
581
747
|
}
|
748
|
+
|
749
|
+
Tkri::attach_bindings root, 'root'
|
750
|
+
end
|
751
|
+
|
752
|
+
# Invokes an "interactive" command (see Settings::BINDINGS).
|
753
|
+
# The command is searched in App, Tabs, Tabsbar, Tab, in this order.
|
754
|
+
def invoke_command(command, event)
|
755
|
+
possible_targets = [self, @tabs, @tabsbar, @tabs.current_tab]
|
756
|
+
possible_targets.each { |target|
|
757
|
+
if target.respond_to?(command, true)
|
758
|
+
target.send(command, event)
|
759
|
+
break
|
760
|
+
end
|
761
|
+
}
|
762
|
+
end
|
763
|
+
|
764
|
+
# Execute is the same as invoke_command() except that we don't
|
765
|
+
# provide an event. It's existence is for aesthetics' sake only.
|
766
|
+
# It is used in menus.
|
767
|
+
def execute(command)
|
768
|
+
invoke_command(command, nil)
|
769
|
+
end
|
770
|
+
|
771
|
+
def interactive_quit e
|
772
|
+
exit
|
582
773
|
end
|
583
774
|
|
584
775
|
def run
|
@@ -587,8 +778,8 @@ class App
|
|
587
778
|
|
588
779
|
# Navigates to some topic. This method simply delegates to the current tab.
|
589
780
|
def go(topic=nil, newtab=false)
|
590
|
-
@tabs.new_tab if newtab and not @tabs.
|
591
|
-
@tabs.
|
781
|
+
@tabs.new_tab if newtab and not @tabs.current_tab.new?
|
782
|
+
@tabs.current_tab.go topic
|
592
783
|
end
|
593
784
|
|
594
785
|
# Sets the text to show in the status bar.
|
@@ -599,29 +790,29 @@ class App
|
|
599
790
|
def refresh_tabsbar
|
600
791
|
@tabsbar.build_buttons if @tabsbar
|
601
792
|
end
|
602
|
-
|
603
|
-
def
|
793
|
+
|
794
|
+
def interactive_search_prev e
|
604
795
|
if @search_word
|
605
|
-
@tabs.
|
796
|
+
@tabs.current_tab.search_prev_word @search_word
|
606
797
|
end
|
607
798
|
end
|
608
|
-
|
609
|
-
def
|
799
|
+
|
800
|
+
def interactive_search_next e
|
610
801
|
if @search_word
|
611
|
-
@tabs.
|
802
|
+
@tabs.current_tab.search_next_word @search_word
|
612
803
|
else
|
613
|
-
|
804
|
+
interactive_initiate_search nil
|
614
805
|
end
|
615
806
|
end
|
616
807
|
|
617
|
-
def
|
808
|
+
def interactive_initiate_search e
|
618
809
|
self.status = 'Type the string to search'
|
619
810
|
entry = TkEntry.new(@root).pack(:fill => 'x').focus
|
620
811
|
['Key-Return', 'Key-KP_Enter'].each do |event|
|
621
812
|
entry.bind(event) {
|
622
813
|
self.status = ''
|
623
814
|
@search_word = entry.get
|
624
|
-
@tabs.
|
815
|
+
@tabs.current_tab.search_next_word entry.get
|
625
816
|
entry.destroy
|
626
817
|
}
|
627
818
|
end
|
@@ -632,7 +823,7 @@ class App
|
|
632
823
|
}
|
633
824
|
end
|
634
825
|
entry.bind('KeyRelease') {
|
635
|
-
@tabs.
|
826
|
+
@tabs.current_tab.highlight_word entry.get
|
636
827
|
}
|
637
828
|
end
|
638
829
|
|
@@ -701,18 +892,34 @@ EOS
|
|
701
892
|
|
702
893
|
def help_key_bindings
|
703
894
|
helpbox('Help: Key bindings', <<EOS)
|
895
|
+
These are the *default* bindings. They are configurable via the 'rc' file.
|
896
|
+
|
704
897
|
Left mouse button
|
705
898
|
Navigate to the topic under the cursor.
|
899
|
+
Ctrl + Left mouse button
|
900
|
+
Navigate to the topic selected (marked) with the mouse.
|
706
901
|
Middle mouse button
|
707
902
|
Navigate to the topic under the cursor. Opens in a new tab.
|
708
903
|
Right mouse button
|
709
904
|
Move back in the history.
|
710
|
-
Ctrl+W. Or
|
905
|
+
Ctrl+W. Or middle mouse button, on a tab button
|
711
906
|
Close the tab (unless this is the only tab).
|
712
907
|
Ctrl+L
|
713
908
|
Move the keyboard focus to the "address" box, where you can type a topic.
|
909
|
+
Ctrl+T
|
910
|
+
New tab.
|
911
|
+
Alt-1 .. Alt-9, Ctrl-PgUp, Ctrl-PgDn
|
912
|
+
Swith to a certain, or to the next/previous one.
|
913
|
+
u
|
914
|
+
Goes "up" one level. That is, if you're browsing Module::Class#method,
|
915
|
+
you'll be directed to Module::Class. Press 'u' again for Module.
|
916
|
+
Enter
|
917
|
+
Go to the topic under the caret, or, if some text is selected, to the
|
918
|
+
topic selected.
|
714
919
|
/
|
715
|
-
Find string in page.
|
920
|
+
Find string in page.
|
921
|
+
n, N
|
922
|
+
Jump to next/previous finds.
|
716
923
|
EOS
|
717
924
|
end
|
718
925
|
|
@@ -737,6 +944,11 @@ Left-clicking on a word doesn't yet send you to a new page. It's
|
|
737
944
|
*releasing* the button that sends you there. This makes it possible to
|
738
945
|
select pieces of code: left-click, then drag, then release; since some
|
739
946
|
text is now selected, Tkri figures out that's all you wanted.
|
947
|
+
|
948
|
+
When using Enter to go to a selected (marked) topic, note that it's easier
|
949
|
+
to hit the Enter of the keypad, with your thumb, because it's near the
|
950
|
+
mouse (provided you're right-handed). As a bonus, you can navigate with one
|
951
|
+
hand only.
|
740
952
|
EOS
|
741
953
|
end
|
742
954
|
|
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.3
|
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-10-
|
12
|
+
date: 2009-10-29 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|