PageRenderTime 27ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/bundles/plugins-trunk/RubyPlugin/src/org/jedit/ruby/ri/RDocSeacher.java

#
Java | 235 lines | 161 code | 34 blank | 40 comment | 24 complexity | f5ca29865bed7203e047eec2375c58eb MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * RDocSeacher.java -
  3. *
  4. * Copyright 2005 Robert McKinnon
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19. */
  20. package org.jedit.ruby.ri;
  21. import org.gjt.sp.jedit.View;
  22. import org.gjt.sp.jedit.jEdit;
  23. import org.gjt.sp.jedit.Macros;
  24. import org.jedit.ruby.ast.Member;
  25. import org.jedit.ruby.ast.Method;
  26. import org.jedit.ruby.structure.TypeAheadPopup;
  27. import org.jedit.ruby.RubyPlugin;
  28. import org.jedit.ruby.utils.CommandUtils;
  29. import javax.swing.*;
  30. import java.awt.event.ActionEvent;
  31. import java.awt.event.KeyEvent;
  32. import java.io.*;
  33. import java.util.*;
  34. /**
  35. * Allows user to search Ruby documentation using ri - Ruby interactive reference.<ul><li>
  36. * Brings up dialog for user to enter search term.</li><li>
  37. * Macro runs ri on term, and reports ri results in another dialog.</li><li>
  38. * Remembers last term searched, and places it in search entry field.</li><li>
  39. * If user has text selected, then that is placed in search entry field instead.</li></ul>
  40. *
  41. * @author robmckinnon at users.sourceforge.net
  42. */
  43. public final class RDocSeacher {
  44. private static final RDocSeacher instance = new RDocSeacher();
  45. private final Map<String, String> termToResult;
  46. /**
  47. * singleton private constructor
  48. */
  49. private RDocSeacher() {
  50. termToResult = new HashMap<String, String>();
  51. }
  52. public static void doSearch(View view) throws IOException, InterruptedException {
  53. instance.performSearch(view);
  54. }
  55. public static void doSearch(View view, String searchTerm) {
  56. try {
  57. instance.searchFor(searchTerm, view);
  58. } catch (IOException e) {
  59. e.printStackTrace();
  60. RubyPlugin.error(e, RDocSeacher.class);
  61. } catch (InterruptedException e) {
  62. e.printStackTrace();
  63. RubyPlugin.error(e, RDocSeacher.class);
  64. }
  65. }
  66. /**
  67. * Performs Ruby documentation search.
  68. */
  69. private void performSearch(View view) throws IOException, InterruptedException {
  70. String term = getSearchTerm(view, view.getTextArea().getSelectedText());
  71. if (term != null) {
  72. jEdit.setProperty("ruby-ri-search-term", term);
  73. searchFor(term, view);
  74. }
  75. }
  76. private void searchFor(String term, View view) throws IOException, InterruptedException {
  77. String result = ri(term);
  78. if(result.startsWith("More than one method matched your request.")) {
  79. List<Member> methods = parseMultipleResults(result);
  80. Member[] members = methods.toArray(new Member[methods.size()]);
  81. new TypeAheadPopup(view, members, members[0], org.jedit.ruby.structure.TypeAheadPopup.SEARCH_POPUP);
  82. } else {
  83. showDialog(view, "", result);
  84. }
  85. }
  86. public static List<Member> parseMultipleResults(String result) {
  87. StringTokenizer lines = new StringTokenizer(result, "\n");
  88. List<Member> methods = new ArrayList<Member>();
  89. while(lines.hasMoreTokens()) {
  90. String line = lines.nextToken();
  91. if(line.startsWith(" ")) {
  92. StringTokenizer tokenizer = new StringTokenizer(line.trim(), ", ");
  93. while(tokenizer.hasMoreTokens()) {
  94. String namespace = null;
  95. String methodName = tokenizer.nextToken();
  96. int index = methodName.lastIndexOf("#");
  97. int otherIndex = methodName.lastIndexOf("::");
  98. index = Math.max(index, otherIndex);
  99. boolean isClassMethod = index == otherIndex;
  100. int adj = isClassMethod ? 2 : 1;
  101. if (index != -1) {
  102. namespace = methodName.substring(0, index);
  103. methodName = methodName.substring(index + adj);
  104. }
  105. Method method = new Method(methodName, null, "none", "none", isClassMethod);
  106. method.setNamespace(namespace);
  107. methods.add(method);
  108. }
  109. }
  110. }
  111. Collections.sort(methods);
  112. return methods;
  113. }
  114. /**
  115. * Runs ri on supplied string search term and returns result string.
  116. */
  117. private String ri(String searchTerm) throws IOException, InterruptedException {
  118. if (searchTerm.length() == 0) {
  119. searchTerm = "-c";
  120. }
  121. if (termToResult.containsKey(searchTerm)) {
  122. return termToResult.get(searchTerm);
  123. } else {
  124. String result;
  125. if (CommandUtils.isWindows()) {
  126. result = CommandUtils.getOutput("ri.bat -T " + '"' + searchTerm + '"', true);
  127. } else {
  128. result = CommandUtils.getOutput("ri -T " + searchTerm, true);
  129. }
  130. if (result.length() == 0) {
  131. result = rri(searchTerm);
  132. }
  133. if (result == null) {
  134. result = jEdit.getProperty("ruby.search-documentation.error");
  135. } else {
  136. termToResult.put(searchTerm, result);
  137. }
  138. return result;
  139. }
  140. }
  141. private static String rri(String searchTerm) throws IOException, InterruptedException {
  142. File resultFile = CommandUtils.getStoragePath("ri_result.txt");
  143. String command = getRriCommand(resultFile, searchTerm);
  144. CommandUtils.getOutput(command, false);
  145. return RubyPlugin.readFile(resultFile);
  146. }
  147. private static String getRriCommand(File resultFile, String searchTerm) throws IOException, InterruptedException {
  148. if (CommandUtils.isWindows()) {
  149. String text = "exec ri.bat -T %1 > " + '"' + resultFile + '"' + '\n';
  150. File commandFile = CommandUtils.getCommandFile("rri.bat", false, text);
  151. return '"' + commandFile.getPath() + '"' + ' ' + '"' + searchTerm + '"';
  152. } else {
  153. String text = "#!/bin/sh\n"
  154. + "ri -T $1 > " + resultFile + '\n';
  155. File commandFile = CommandUtils.getCommandFile("rri.sh", false, text);
  156. return commandFile.getPath() + ' ' + searchTerm;
  157. }
  158. }
  159. private static JScrollPane getScrollPane(JTextArea label, Action closeAction) {
  160. JScrollPane scrollPane = new JScrollPane(label);
  161. final String CLOSE = "close";
  162. scrollPane.getActionMap().put(CLOSE, closeAction);
  163. InputMap inputMap = scrollPane.getInputMap();
  164. inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), CLOSE);
  165. inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), CLOSE);
  166. inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), CLOSE);
  167. return scrollPane;
  168. }
  169. private void showDialog(View frame, String title, String text) {
  170. final JDialog dialog = new JDialog(frame, title, false);
  171. JTextArea label = new JTextArea(text);
  172. label.setEditable(true);
  173. label.setBackground(dialog.getContentPane().getBackground());
  174. JScrollPane pane = getScrollPane(label, new AbstractAction() {
  175. public void actionPerformed(ActionEvent e) {
  176. dialog.setVisible(false);
  177. dialog.dispose();
  178. }
  179. });
  180. dialog.setContentPane(pane);
  181. dialog.pack();
  182. int height = dialog.getHeight();
  183. if (dialog.getHeight() > frame.getHeight() * .8) {
  184. height = (int) (frame.getHeight() * .8);
  185. }
  186. dialog.setSize((int) (dialog.getWidth() * 1.05), height);
  187. dialog.setLocationRelativeTo(frame);
  188. dialog.setVisible(true);
  189. }
  190. /**
  191. * Displays dialog for user to enter search term.
  192. */
  193. private static String getSearchTerm(View view, String term) {
  194. if (term == null) {
  195. term = jEdit.getProperty("ruby-ri-search-term", "");
  196. }
  197. String label = jEdit.getProperty("ruby.search-documentation.dialog.label");
  198. term = Macros.input(view, label, term);
  199. return term;
  200. }
  201. }