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