tkri 0.9.3 → 0.9.4
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/lib/tkri.rb +178 -67
- metadata +2 -2
data/lib/tkri.rb
CHANGED
@@ -44,7 +44,7 @@ module Tkri
|
|
44
44
|
'mswin' => 'qri.bat -f ansi "%s" 2>&1',
|
45
45
|
}
|
46
46
|
|
47
|
-
|
47
|
+
VISUALS = {
|
48
48
|
# The '__base__' attibutes are applied for every textfield and textarea.
|
49
49
|
# Set the background color and font to whatever you like.
|
50
50
|
#
|
@@ -53,14 +53,16 @@ module Tkri
|
|
53
53
|
# name (i.e., one of: 'courier', 'times', 'helvetica') at the end to serve
|
54
54
|
# as a fallback.
|
55
55
|
'__base__' => { :background => '#ffeeff', :font => { :family => ['Bitstream Vera Sans Mono', 'Menlo', 'Monaco', 'Courier'], :size => 10 } },
|
56
|
-
'bold' => { :foreground => 'blue' },
|
57
|
-
'italic' => { :foreground => '#6b8e23' }, # greenish
|
58
|
-
'code' => { :foreground => '#1874cd' }, # blueish
|
59
|
-
'header2' => { :background => '#ffe4b5', :font => { :family => ['Geneva', 'Arial', 'Helvetica'], :size => 12 } },
|
60
|
-
'header3' => { :background => '#ffe4b5', :font => { :family => ['Geneva', 'Arial', 'Helvetica'], :size => 14 } },
|
61
|
-
'keyword' => { :foreground => 'red' },
|
62
|
-
'search' => { :background => 'yellow' },
|
63
|
-
'hidden' => { :elide => true },
|
56
|
+
'bold' => { :foreground => 'blue', :is_tag => true },
|
57
|
+
'italic' => { :foreground => '#6b8e23', :is_tag => true }, # greenish
|
58
|
+
'code' => { :foreground => '#1874cd', :is_tag => true }, # blueish
|
59
|
+
'header2' => { :background => '#ffe4b5', :font => { :family => ['Geneva', 'Arial', 'Helvetica'], :size => 12 }, :is_tag => true },
|
60
|
+
'header3' => { :background => '#ffe4b5', :font => { :family => ['Geneva', 'Arial', 'Helvetica'], :size => 14 }, :is_tag => true },
|
61
|
+
'keyword' => { :foreground => 'red', :is_tag => true },
|
62
|
+
'search' => { :background => 'yellow', :is_tag => true },
|
63
|
+
'hidden' => { :elide => true, :is_tag => true},
|
64
|
+
'tab_button' => { :padx => 10, :font => { :family => ['Bitstream Vera Sans Mono', 'Menlo', 'Monaco', 'Courier'], :size => 10 } },
|
65
|
+
'go_button' => { :padx => 20 },
|
64
66
|
}
|
65
67
|
|
66
68
|
BINDINGS = {
|
@@ -113,6 +115,8 @@ module Tkri
|
|
113
115
|
# History.
|
114
116
|
'b1013' => { :key => 'ButtonRelease-3', :source => 'info', :command => 'interactive_history_back' },
|
115
117
|
'b1014' => { :key => 'Key-BackSpace', :source => 'info', :command => 'interactive_history_back', :cancel_default => true },
|
118
|
+
'b1014b' => { :key => 'Alt-Key-Left', :source => 'root', :command => 'interactive_history_back', :cancel_default => true },
|
119
|
+
'b1014c' => { :key => 'Alt-Key-Right', :source => 'root', :command => 'interactive_history_forward', :cancel_default => true },
|
116
120
|
|
117
121
|
# Tk doesn't support read-only rext widgets. So for every "ascii" global binding we also
|
118
122
|
# need to duplicate it on the 'info' widget, :cancel_default'ing it.
|
@@ -142,7 +146,7 @@ module Tkri
|
|
142
146
|
f.puts "# You may erase any setting in this file for which you want to use"
|
143
147
|
f.puts "# the default value."
|
144
148
|
f.puts "#"
|
145
|
-
f.puts({ 'command' => COMMAND, '
|
149
|
+
f.puts({ 'command' => COMMAND, 'visuals' => VISUALS, 'bindings' => BINDINGS }.to_yaml)
|
146
150
|
end
|
147
151
|
end
|
148
152
|
|
@@ -154,7 +158,7 @@ module Tkri
|
|
154
158
|
|
155
159
|
module Settings
|
156
160
|
COMMAND = DefaultSettings::COMMAND.dup
|
157
|
-
|
161
|
+
VISUALS = DefaultSettings::VISUALS.dup
|
158
162
|
BINDINGS = DefaultSettings::BINDINGS
|
159
163
|
|
160
164
|
# Load the settings from the 'rc' file. We merge them into the existing settings.
|
@@ -164,33 +168,84 @@ module Tkri
|
|
164
168
|
settings = YAML.load_file(Tkri.get_rc_file_path)
|
165
169
|
if settings.instance_of? Hash
|
166
170
|
COMMAND.merge!(settings['command']) if settings['command']
|
167
|
-
|
171
|
+
VISUALS.merge!(settings['visuals']) if settings['visuals']
|
168
172
|
BINDINGS.merge!(settings['bindings']) if settings['bindings']
|
169
173
|
end
|
170
174
|
end
|
171
175
|
end
|
176
|
+
|
177
|
+
# get_configuration() converts any of the VISUAL hashes, above, to a hash suitable
|
178
|
+
# for use in Tk. Corrently, it only converts the :font attribute to a TkFont instance.
|
179
|
+
def self.get_configuration(name)
|
180
|
+
h = VISUALS[name].dup
|
181
|
+
h.delete(:is_tag)
|
182
|
+
if h[:font].instance_of? Hash
|
183
|
+
h[:font] = h[:font].dup
|
184
|
+
if h[:font][:family]
|
185
|
+
availables = TkFont.families.map { |s| s.downcase }
|
186
|
+
desired = Array(h[:font][:family]).map { |s| s.downcase }
|
187
|
+
# Select the first family available on this system.
|
188
|
+
h[:font][:family] = (desired & availables).first || 'courier'
|
189
|
+
end
|
190
|
+
h[:font] = TkFont.new(h[:font])
|
191
|
+
end
|
192
|
+
return h
|
193
|
+
end
|
172
194
|
end
|
173
195
|
|
174
196
|
HistoryEntry = Struct.new(:topic, :cursor, :yview)
|
175
197
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
198
|
+
class History
|
199
|
+
def initialize
|
200
|
+
@arr = []
|
201
|
+
@current = -1
|
202
|
+
end
|
203
|
+
|
204
|
+
def size
|
205
|
+
@arr.size
|
206
|
+
end
|
207
|
+
|
208
|
+
def current
|
209
|
+
if @current >= 0
|
210
|
+
@arr[@current]
|
211
|
+
else
|
212
|
+
nil
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def back
|
217
|
+
if @current > 0
|
218
|
+
@current -= 1
|
219
|
+
end
|
220
|
+
current
|
221
|
+
end
|
222
|
+
|
223
|
+
def foreward
|
224
|
+
if @current < @arr.size - 1
|
225
|
+
@current += 1
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def add(entry)
|
230
|
+
@current += 1
|
231
|
+
@arr[@current] = entry
|
232
|
+
# Adding an entry removes all entries in the "future".
|
233
|
+
@arr.slice!(@current + 1, @arr.size)
|
234
|
+
end
|
235
|
+
|
236
|
+
def at_beginning
|
237
|
+
@current <= 0
|
238
|
+
end
|
239
|
+
|
240
|
+
def at_end
|
241
|
+
@current == @arr.size - 1;
|
242
|
+
end
|
191
243
|
end
|
192
244
|
|
193
245
|
# Attachs Settings::BINDINGS to a certain widget.
|
246
|
+
#
|
247
|
+
# Ideally this should be a method of TkWidget, but for some reason widgets don't
|
248
|
+
# seem to inherit methods I define on TkWidget.
|
194
249
|
def self.attach_bindings(widget, widget_id_string)
|
195
250
|
Tkri::Settings::BINDINGS.each_pair { |ignored_key, b|
|
196
251
|
if (b[:source] == widget_id_string)
|
@@ -229,13 +284,14 @@ class Tab < TkFrame
|
|
229
284
|
addressbar = TkFrame.new(self) { |ab|
|
230
285
|
pack :side => 'top', :fill => 'x'
|
231
286
|
TkButton.new(ab) {
|
287
|
+
configure Settings::get_configuration('go_button')
|
232
288
|
text 'Go'
|
233
289
|
command { app.go }
|
234
290
|
pack :side => 'right'
|
235
291
|
}
|
236
292
|
}
|
237
293
|
@address = TkEntry.new(addressbar) {
|
238
|
-
configure
|
294
|
+
configure Settings::get_configuration('__base__')
|
239
295
|
configure :width => 30
|
240
296
|
pack :side => 'left', :expand => true, :fill => 'both'
|
241
297
|
}
|
@@ -245,7 +301,7 @@ class Tab < TkFrame
|
|
245
301
|
#
|
246
302
|
_frame = self
|
247
303
|
@info = TkText.new(self) { |t|
|
248
|
-
configure
|
304
|
+
configure Settings::get_configuration('__base__')
|
249
305
|
pack :side => 'left', :fill => 'both', :expand => true
|
250
306
|
TkScrollbar.new(_frame) { |s|
|
251
307
|
pack :side => 'right', :fill => 'y'
|
@@ -254,18 +310,16 @@ class Tab < TkFrame
|
|
254
310
|
}
|
255
311
|
}
|
256
312
|
|
257
|
-
Settings::
|
258
|
-
|
313
|
+
Settings::VISUALS.each do |name, hash|
|
314
|
+
if hash[:is_tag]
|
315
|
+
@info.tag_configure(name, Settings::get_configuration(name))
|
316
|
+
end
|
259
317
|
end
|
260
318
|
|
261
319
|
Tkri.attach_bindings @address, 'addressbox'
|
262
320
|
Tkri.attach_bindings @info, 'info'
|
263
321
|
|
264
|
-
@history =
|
265
|
-
end
|
266
|
-
|
267
|
-
def interactive_history_back e
|
268
|
-
back
|
322
|
+
@history = History.new
|
269
323
|
end
|
270
324
|
|
271
325
|
def interactive_goto_topic_in_addressbox e
|
@@ -288,7 +342,7 @@ class Tab < TkFrame
|
|
288
342
|
end
|
289
343
|
end
|
290
344
|
|
291
|
-
# It
|
345
|
+
# It seems RubyTk doesn't support the the getSelected method for Text widgets.
|
292
346
|
# So here's a method of our own to get the selection.
|
293
347
|
def get_selection
|
294
348
|
begin
|
@@ -510,22 +564,49 @@ class Tab < TkFrame
|
|
510
564
|
end
|
511
565
|
|
512
566
|
# Navigates to some topic.
|
513
|
-
def go(topic=nil
|
567
|
+
def go(topic=nil)
|
514
568
|
topic = (topic || @address.get).strip
|
515
569
|
return if topic.empty?
|
516
|
-
if @topic and not skip_history
|
517
|
-
# Push current topic into history.
|
518
|
-
@history << HistoryEntry.new(@topic, @info.index('insert'), @info.yview[0])
|
519
|
-
end
|
520
570
|
@topic = fixup_topic(topic)
|
521
|
-
|
571
|
+
# First, save the cursor position in the current history entry.
|
572
|
+
store_in_history
|
573
|
+
# Next, add a new entry to the history.
|
574
|
+
@history.add HistoryEntry.new(@topic, nil, nil)
|
575
|
+
# Finally, load the topic.
|
576
|
+
_load_topic @topic
|
577
|
+
end
|
578
|
+
|
579
|
+
# Call this method before switching to another topic. This
|
580
|
+
# method saves the cursor position in the history.
|
581
|
+
def store_in_history
|
582
|
+
if current = @history.current
|
583
|
+
current.cursor = @info.index('insert')
|
584
|
+
current.yview = @info.yview[0]
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
# Call this method after moving fack and forth in the history.
|
589
|
+
# This method restores the topic and cursor position recorded
|
590
|
+
# in the current history entry.
|
591
|
+
def restore_from_history
|
592
|
+
if current = @history.current
|
593
|
+
@topic = current.topic
|
594
|
+
_load_topic(topic) do
|
595
|
+
@info.yview_moveto current.yview
|
596
|
+
set_cursor current.cursor
|
597
|
+
end
|
598
|
+
end
|
599
|
+
end
|
600
|
+
|
601
|
+
def _load_topic(topic)
|
602
|
+
@app.status = 'Loading "%s"...' % topic
|
522
603
|
@address.delete('0', 'end')
|
523
|
-
@address.insert('end',
|
604
|
+
@address.insert('end', topic)
|
524
605
|
focus_address
|
525
606
|
# We need to give our GUI a chance to redraw itself, so we run the
|
526
607
|
# time-consuming 'ri' command "in the next go".
|
527
608
|
TkAfter.new 100, 1 do
|
528
|
-
ri = @app.fetch_ri(
|
609
|
+
ri = @app.fetch_ri(topic)
|
529
610
|
set_ansi_text(ri)
|
530
611
|
@app.refresh_tabsbar
|
531
612
|
@app.status = ''
|
@@ -534,14 +615,22 @@ class Tab < TkFrame
|
|
534
615
|
yield if block_given?
|
535
616
|
end.start
|
536
617
|
end
|
618
|
+
|
619
|
+
# Navigate to the previous topic in history.
|
620
|
+
def interactive_history_back e
|
621
|
+
if not @history.at_beginning
|
622
|
+
store_in_history
|
623
|
+
@history.back
|
624
|
+
restore_from_history
|
625
|
+
end
|
626
|
+
end
|
537
627
|
|
538
|
-
# Navigate to the
|
539
|
-
def
|
540
|
-
if
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
end
|
628
|
+
# Navigate to the next topic in history.
|
629
|
+
def interactive_history_forward e
|
630
|
+
if not @history.at_end
|
631
|
+
store_in_history
|
632
|
+
@history.foreward
|
633
|
+
restore_from_history
|
545
634
|
end
|
546
635
|
end
|
547
636
|
|
@@ -586,11 +675,13 @@ class Tabsbar < TkFrame
|
|
586
675
|
@buttons = []
|
587
676
|
@tabs.each_with_index do |tab, i|
|
588
677
|
b = TkButton.new(self, :text => (tab.topic || '<new>')).pack :side => 'left'
|
678
|
+
b.configure Settings::get_configuration('tab_button')
|
589
679
|
b.command { set_current_tab_by_index i }
|
590
680
|
Tkri.attach_bindings b, 'tabbutton'
|
591
681
|
@buttons << b
|
592
682
|
end
|
593
|
-
plus = TkButton.new(self, :text => '+').pack :side => 'left'
|
683
|
+
plus = TkButton.new(self, :text => '+').pack :side => 'left', :padx => 10
|
684
|
+
plus.configure Settings::get_configuration('tab_button')
|
594
685
|
plus.command { @tabs.new_tab }
|
595
686
|
@buttons << plus
|
596
687
|
set_current_tab_by_index @tabs.current_tab_as_index
|
@@ -621,7 +712,6 @@ class Tabs < TkFrame
|
|
621
712
|
tab.focus_address
|
622
713
|
@tabs << tab
|
623
714
|
set_current_tab_by_index(@tabs.size - 1, true)
|
624
|
-
# @app.refresh_tabsbar
|
625
715
|
end
|
626
716
|
|
627
717
|
def interactive_new_tab e
|
@@ -844,10 +934,22 @@ class App
|
|
844
934
|
if text == "nil\n"
|
845
935
|
text = 'Topic "%s" not found.' % topic
|
846
936
|
end
|
937
|
+
text = _post_process_text(text)
|
847
938
|
@ri_cache[topic] = text
|
848
939
|
@cached_topics << topic
|
849
940
|
end
|
850
941
|
|
942
|
+
# Remove the oldest topic from the cache
|
943
|
+
if @cached_topics.length > 20
|
944
|
+
@ri_cache.delete @cached_topics.shift
|
945
|
+
end
|
946
|
+
|
947
|
+
return text
|
948
|
+
end
|
949
|
+
|
950
|
+
# Enhance the ri text a bit.
|
951
|
+
def _post_process_text(text)
|
952
|
+
|
851
953
|
# Make the "Multiple choices" output easier to read.
|
852
954
|
if text.match /Multiple choices/
|
853
955
|
text.gsub! /,\s+/, "\n"
|
@@ -855,18 +957,27 @@ class App
|
|
855
957
|
text.gsub! /\n/, "\n "
|
856
958
|
end
|
857
959
|
|
858
|
-
#
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
960
|
+
# Highlight the names of included modules.
|
961
|
+
bold_on = "\x1b[1m"
|
962
|
+
bold_off = "\x1b[0m"
|
963
|
+
parts = text.split /([\r\n]\S*Includes:.*?[\r\n][\r\n])/m
|
964
|
+
parts.map! { |s|
|
965
|
+
if s =~ /[\r\n]\S*Includes:/
|
966
|
+
# Modules have parentheses following them.
|
967
|
+
s.gsub! /(\S+)\(/, bold_on + '\1' + bold_off + '('
|
968
|
+
else
|
969
|
+
s
|
970
|
+
end
|
971
|
+
}
|
972
|
+
text = parts.join
|
973
|
+
|
863
974
|
return text
|
864
975
|
end
|
865
976
|
|
866
977
|
def helpbox(title, text)
|
867
978
|
w = TkToplevel.new(:title => title)
|
868
979
|
t = TkText.new(w, :height => text.count("\n"), :width => 80).pack.insert('1.0', text)
|
869
|
-
t.configure
|
980
|
+
t.configure Settings::get_configuration('__base__')
|
870
981
|
TkButton.new(w, :text => 'Close', :command => proc { w.destroy }).pack
|
871
982
|
end
|
872
983
|
|
@@ -900,16 +1011,18 @@ Ctrl + Left mouse button
|
|
900
1011
|
Navigate to the topic selected (marked) with the mouse.
|
901
1012
|
Middle mouse button
|
902
1013
|
Navigate to the topic under the cursor. Opens in a new tab.
|
903
|
-
Right mouse button
|
904
|
-
Move back in the history.
|
1014
|
+
Right mouse button, Backspace, Alt+Left
|
1015
|
+
Move back in the history.
|
1016
|
+
Alt+Right
|
1017
|
+
Move foreward in the history.
|
905
1018
|
Ctrl+W. Or middle mouse button, on a tab button
|
906
1019
|
Close the tab (unless this is the only tab).
|
907
1020
|
Ctrl+L
|
908
1021
|
Move the keyboard focus to the "address" box, where you can type a topic.
|
909
1022
|
Ctrl+T
|
910
1023
|
New tab.
|
911
|
-
Alt
|
912
|
-
Swith to a certain, or to the next/previous one.
|
1024
|
+
Alt+1 .. Alt+9, Ctrl+PgUp, Ctrl+PgDn
|
1025
|
+
Swith to a certain tab, or to the next/previous one.
|
913
1026
|
u
|
914
1027
|
Goes "up" one level. That is, if you're browsing Module::Class#method,
|
915
1028
|
you'll be directed to Module::Class. Press 'u' again for Module.
|
@@ -983,8 +1096,6 @@ Here's a list of known issues / bugs:
|
|
983
1096
|
|
984
1097
|
ON THE WINDOWS PLATFORM:
|
985
1098
|
|
986
|
-
* Tkri looks ugly.
|
987
|
-
|
988
1099
|
* The mouse wheel works only if the keyboard focus is in the
|
989
1100
|
textarea. That's unfortunate. It's a Tk issue, not Tkri's.
|
990
1101
|
|
@@ -994,7 +1105,7 @@ ON THE WINDOWS PLATFORM:
|
|
994
1105
|
|
995
1106
|
ALL PLATFORMS:
|
996
1107
|
|
997
|
-
*
|
1108
|
+
* No known issues.
|
998
1109
|
EOS
|
999
1110
|
end
|
1000
1111
|
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.4
|
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-30 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|