Class: Tkri::App

Inherits:
Object
  • Object
show all
Defined in:
lib/tkri.rb

Instance Method Summary collapse

Constructor Details

#initializeApp

Returns a new instance of App.



806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
# File 'lib/tkri.rb', line 806

def initialize
  @root = root = TkRoot.new { title 'Tkri' }
  @search_word = nil
  
  Tkri.the_application = self
  
  Settings.load
 
  menu_spec = [
    [['File', 0],
      ['New tab', proc { execute 'interactive_new_tab' }, 0, 'Ctrl+T' ],
      ['Close tab', proc { execute 'interactive_close_tab' }, 0, 'Ctrl+W' ],
      '---',
      ['Quit', proc { execute 'interactive_quit' }, 0, 'Ctrl+Q' ]],
    [['Search', 0],
      ['Search', proc { execute 'interactive_initiate_search' }, 0, '/'],
      ['Repeat search', proc { execute 'interactive_search_next' }, 0, 'n'],
      ['Repeat backwards', proc { execute 'interactive_search_prev' }, 7, 'N']],
    # The following :menu_name=>'help' has no effect, but it should have...
    # probably a bug in RubyTK.
    [['Help', 0, { :menu_name => 'help' }],
      ['Overview', proc { help_overview }, 0],
      ['Key bindings', proc { help_key_bindings }, 0],
      ['Tips and tricks', proc { help_tips_and_tricks }, 0],
      ['About the $HOME/.tkrirc file', proc { help_rc }, 0],
      ['Known issues', proc { help_known_issues }, 0]],
  ]
  TkMenubar.new(root, menu_spec).pack(:side => 'top', :fill => 'x')

  @tabs = Tabs.new(root, self) {
    pack :side => 'top', :fill => 'both', :expand => true
  }
  @tabsbar = Tabsbar.new(root, @tabs) {
    pack :side => 'top', :fill => 'x', :before => @tabs
  }
  @statusbar = TkLabel.new(root, :anchor => 'w') {
    pack :side => 'bottom', :fill => 'x'
  }

  Tkri::attach_bindings root, 'root'
end

Instance Method Details

#_post_process_text(text) ⇒ Object

Enhance the ri text a bit.



957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
# File 'lib/tkri.rb', line 957

def _post_process_text(text)

  # Make the "Multiple choices" output easier to read.
  if text.match /Multiple choices/
    text.gsub! /,\s+/, "\n"
    text.gsub! /^ */,  ""
    text.gsub! /\n/,   "\n     "
  end

  # Highlight the names of included modules.
  bold_on  = "\x1b[1m"
  bold_off = "\x1b[0m"
  parts = text.split /([\r\n]\S*Includes:.*?[\r\n][\r\n])/m
  parts.map! { |s|
    if s =~ /[\r\n]\S*Includes:/
      # Modules have parentheses following them.
      s.gsub! /(\S+)\(/, bold_on + '\1' + bold_off + '('
    else
      s
    end
  }
  text = parts.join

  return text
end

#execute(command) ⇒ Object

Execute is the same as invoke_command() except that we don’t provide an event. It’s existence is for aesthetics’ sake only. It is used in menus.



863
864
865
# File 'lib/tkri.rb', line 863

def execute(command)
  invoke_command(command, nil)
end

#fetch_ri(topic) ⇒ Object

Executes the ‘ri’ command and returns its output.



927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
# File 'lib/tkri.rb', line 927

def fetch_ri topic
  if !@ri_cache
    @ri_cache = {}
    @cached_topics = []
  end

  return @ri_cache[topic] if @ri_cache[topic]

  command = Settings::COMMAND.select { |k,v| RUBY_PLATFORM.index(k) }.first.to_a[1] || Settings::COMMAND['__default__']
  text = Kernel.`(command % topic)  # `
  if $? != 0
    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]
  else
    if text == "nil\n"
      text = 'Topic "%s" not found.' % topic
    end
    text = _post_process_text(text)
    @ri_cache[topic] = text
    @cached_topics << topic
  end

  # Remove the oldest topic from the cache
  if @cached_topics.length > 20
    @ri_cache.delete @cached_topics.shift
  end

  return text
end

#go(topic = nil, newtab = false) ⇒ Object

Navigates to some topic. This method simply delegates to the current tab.



876
877
878
879
# File 'lib/tkri.rb', line 876

def go(topic=nil, newtab=false)
  @tabs.new_tab if newtab and not @tabs.current_tab.new?
  @tabs.current_tab.go topic
end

#help_key_bindingsObject



1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
# File 'lib/tkri.rb', line 1010

def help_key_bindings
  helpbox('Help: Key bindings', <<EOS)
These are the *default* bindings. They are configurable via the 'rc' file.

Left mouse button
  Navigate to the topic under the cursor.
Ctrl + Left mouse button
  Navigate to the topic selected (marked) with the mouse.
Middle mouse button
  Navigate to the topic under the cursor. Opens in a new tab.
Right mouse button, Backspace, Alt+Left
  Move back in the history.
Alt+Right
  Move foreward in the history.
Ctrl+W. Or middle mouse button, on a tab button
  Close the tab (unless this is the only tab).
Ctrl+L
  Move the keyboard focus to the "address" box, where you can type a topic.
Ctrl+T
  New tab.
Alt+1 .. Alt+9, Ctrl+PgUp, Ctrl+PgDn
  Swith to a certain tab, or to the next/previous one.
u
  Goes "up" one level. That is, if you're browsing Module::Class#method,
  you'll be directed to Module::Class. Press 'u' again for Module.
Enter
  Go to the topic under the caret, or, if some text is selected, to the
  topic selected.
/
  Find string in page. 
n, N
  Jump to next/previous finds.
EOS
end

#help_known_issuesObject



1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
# File 'lib/tkri.rb', line 1099

def help_known_issues
  helpbox('Help: Known issues', <<EOS)
Here's a list of known issues / bugs:

ON THE WINDOWS PLATFORM:

* The mouse wheel works only if the keyboard focus is in the
textarea. That's unfortunate. It's a Tk issue, not Tkri's.

* If your $HOME variable contains non-ASCII charcaters, Tkri
seems not to be able to deal with the 'rc' file. It's a Ruby
issue(?).

ALL PLATFORMS:

* No known issues.
EOS
end

#help_overviewObject



990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
# File 'lib/tkri.rb', line 990

def help_overview
  helpbox('Help: Overview', <<EOS)
ABOUT

Tkri (pronounce TIK-ri) is a GUI front-end to the 'ri', or
'qri', executables. By default it uses 'qri', which is part
of the Fast-RI package.

Tkri displays the output of that program in a window where
each work is "hyperlinked".

USAGE

Launch tkri by typing 'tkri' at the operating system prompt. You
can provide a starting topic as an argument on the command line.
Inside the application, type the topic you wish to go to at the
address bar, or click on a word in the main text.
EOS
end

#help_rcObject



1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
# File 'lib/tkri.rb', line 1074

def help_rc
  helpbox('Help: RC', <<EOS)
Tkri has some settings. E.g., the colors and fonts it uses.

These settings are hard-coded in the source code. But you can
override them by having an 'rc' file in your home folder. On
your system this file is here:

  #{Tkri.get_rc_file_path}

(If it's at a weird place, set your $HOME environment variable.)

Of course, you're a busy person and don't have time to write
this file from scratch. So you're going to tell Tkri to write
this file for you; When you type:

  tkri --dump-rc

you're telling Tkri to dump all its default settings into that
file. Then edit this file to your liking using your text editor.
Finally, run tkri; it will automatically merge the settings from
this file onto the hard-coded ones.
EOS
end

#help_tips_and_tricksObject



1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
# File 'lib/tkri.rb', line 1045

def help_tips_and_tricks
  helpbox('Help: Tips and tricks', <<EOS)
Some random tips:

Type '/' to quickly highlight a string in the page. (If the
string happens to be off-screen, hit ENTER to jump to it.)

Ctrl+L is probably the fastest way to move the keyboard
focus to the "address box".

The references for "Hash", "Array" and "String" are the most
sought-after, so instead of typing their full name in the address
box you can just type the letters h, a or s, respectively.

You can type the topic(s) directly on the command line;
e.g., "tkri Array.flatten sort_by"

Left-clicking on a word doesn't yet send you to a new page. It's
*releasing* the button that sends you there. This makes it possible to
select pieces of code: left-click, then drag, then release; since some
text is now selected, Tkri figures out that's all you wanted.

When using Enter to go to a selected (marked) topic, note that it's easier
to hit the Enter of the keypad, with your thumb, because it's near the
mouse (provided you're right-handed). As a bonus, you can navigate with one
hand only.
EOS
end

#helpbox(title, text) ⇒ Object



983
984
985
986
987
988
# File 'lib/tkri.rb', line 983

def helpbox(title, text)
  w = TkToplevel.new(:title => title)
  t = TkText.new(w, :height => text.count("\n"), :width => 80).pack.insert('1.0', text)
  t.configure Settings::get_configuration('__base__')
  TkButton.new(w, :text => 'Close', :command => proc { w.destroy }).pack
end

#interactive_initiate_search(e) ⇒ Object



904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
# File 'lib/tkri.rb', line 904

def interactive_initiate_search e
  self.status = 'Type the string to search'
  entry = TkEntry.new(@root).pack(:fill => 'x').focus
  ['Key-Return', 'Key-KP_Enter'].each do |event|
    entry.bind(event) {
      self.status = ''
      @search_word = entry.get
      @tabs.current_tab.search_next_word entry.get
      entry.destroy
    }
  end
  ['Key-Escape', 'FocusOut'].each do |event|
    entry.bind(event) {
      self.status = ''
      entry.destroy
    }
  end
  entry.bind('KeyRelease') {
    @tabs.current_tab.highlight_word entry.get
  }
end

#interactive_quit(e) ⇒ Object



867
868
869
# File 'lib/tkri.rb', line 867

def interactive_quit e
  exit
end

#interactive_search_next(e) ⇒ Object



896
897
898
899
900
901
902
# File 'lib/tkri.rb', line 896

def interactive_search_next e
  if @search_word
    @tabs.current_tab.search_next_word @search_word
  else
    interactive_initiate_search nil
  end
end

#interactive_search_prev(e) ⇒ Object



890
891
892
893
894
# File 'lib/tkri.rb', line 890

def interactive_search_prev e
  if @search_word
    @tabs.current_tab.search_prev_word @search_word
  end
end

#invoke_command(command, event) ⇒ Object

Invokes an “interactive” command (see Settings::BINDINGS). The command is searched in App, Tabs, Tabsbar, Tab, in this order.



850
851
852
853
854
855
856
857
858
# File 'lib/tkri.rb', line 850

def invoke_command(command, event)
  possible_targets = [self, @tabs, @tabsbar, @tabs.current_tab]
  possible_targets.each { |target|
    if target.respond_to?(command, true)
      target.send(command, event)
      break
    end
  }
end

#refresh_tabsbarObject



886
887
888
# File 'lib/tkri.rb', line 886

def refresh_tabsbar
  @tabsbar.build_buttons if @tabsbar
end

#runObject



871
872
873
# File 'lib/tkri.rb', line 871

def run
  Tk.mainloop
end

#status=(status) ⇒ Object

Sets the text to show in the status bar.



882
883
884
# File 'lib/tkri.rb', line 882

def status=(status)
  @statusbar.configure(:text => status)
end