PageRenderTime 39ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/bundles/plugins-trunk/RubyPlugin/src/org/jedit/ruby/completion/RubyKeyBindings.java

#
Java | 234 lines | 177 code | 35 blank | 22 comment | 79 complexity | 662e3f7b30f1fae2c0e76f5a8ef0b1fb 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. * RubyKeyBindings.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.completion;
  21. import org.gjt.sp.jedit.gui.KeyEventWorkaround;
  22. import org.gjt.sp.jedit.textarea.JEditTextArea;
  23. import org.gjt.sp.jedit.textarea.Selection;
  24. import org.jedit.ruby.RubyPlugin;
  25. import org.jedit.ruby.structure.RubyToken;
  26. import org.jedit.ruby.structure.BufferChangeHandler;
  27. import org.jedit.ruby.utils.CharCaretListener;
  28. import org.jedit.ruby.utils.EditorView;
  29. import java.awt.event.KeyAdapter;
  30. import java.awt.event.KeyEvent;
  31. import java.util.Arrays;
  32. import java.util.List;
  33. /**
  34. * Manages our key bindings.
  35. */
  36. public final class RubyKeyBindings extends KeyAdapter {
  37. private static final List<String> pairs = Arrays.asList("()", "[]", "{}", "''", "\"\"", "//");
  38. private static final char NIL_CHAR = (char)-1;
  39. private final JEditTextArea textArea;
  40. public RubyKeyBindings(JEditTextArea textArea) {
  41. this.textArea = textArea;
  42. }
  43. public void keyPressed(KeyEvent e) {
  44. BufferChangeHandler.instance().setGotoPreviousEdit(false);
  45. }
  46. public void keyReleased(KeyEvent e) {
  47. }
  48. public final void keyTyped(KeyEvent e) {
  49. if (isRuby()) {
  50. e = KeyEventWorkaround.processKeyEvent(e);
  51. keyTypedInRubyText(e);
  52. }
  53. }
  54. private void keyTypedInRubyText(KeyEvent e) {
  55. if (isBackspace(e)) {
  56. handleBackspace();
  57. } else if (isCharacter(e)) {
  58. handleCharacter();
  59. }
  60. }
  61. private void handleBackspace() {
  62. if (CharCaretListener.hasCharLastBehind() && !ignoreBackspace()) {
  63. boolean done = false;
  64. for (String pair : pairs) {
  65. done = removePair(pair);
  66. if (done) break;
  67. }
  68. if (!done) {
  69. removePair("||");
  70. }
  71. }
  72. }
  73. private void handleCharacter() {
  74. boolean done = false;
  75. if (!ignoreCharacter()) {
  76. for (String pair : pairs) {
  77. done = addPair(pair);
  78. if (done) break;
  79. }
  80. if (!done) {
  81. if (behind() == '|') {
  82. if (lastBehind() == '{' && ahead() == '}') {
  83. done = addPair("||");
  84. } else {
  85. EditorView view = RubyPlugin.getActiveView();
  86. int doIndex = view.getLineUpToCaret().indexOf(" do ");
  87. if (view.getCaretPosition() == doIndex + 5) {
  88. done = addPair("||");
  89. }
  90. }
  91. }
  92. }
  93. }
  94. if (!done) {
  95. for (String pair : pairs) {
  96. done = removeExtraEnd(pair);
  97. if (done) break;
  98. }
  99. if(!done) {
  100. removeExtraEnd("||");
  101. }
  102. }
  103. }
  104. private boolean removePair(String pair) {
  105. if (charLastBehind() == pair.charAt(0) && charAhead() == pair.charAt(1)) {
  106. removeNextChar();
  107. return true;
  108. } else {
  109. return false;
  110. }
  111. }
  112. private boolean addPair(String pair) {
  113. char start = pair.charAt(0);
  114. char end = pair.charAt(1);
  115. if (!Character.isLetter(ahead()) && behind() == start && ahead() != end && (start != end || lastBehind() != start)) {
  116. int position = textArea.getCaretPosition();
  117. Selection.Range range = new Selection.Range(position - 1, position);
  118. textArea.setSelection(range);
  119. textArea.setSelectedText(pair);
  120. textArea.setCaretPosition(position);
  121. return true;
  122. } else {
  123. return false;
  124. }
  125. }
  126. private boolean removeExtraEnd(String pair) {
  127. char start = pair.charAt(0);
  128. char end = pair.charAt(1);
  129. boolean done = false;
  130. if (behind() == end && ahead() == end) {
  131. if (lastBehind() == start) {
  132. removeNextChar();
  133. done = true;
  134. } else if(ahead() == '|') {
  135. String line = RubyPlugin.getActiveView().getLineUpToCaret();
  136. if(line.indexOf(" do |") != -1 || line.indexOf("{|") != -1 || line.indexOf("{ |") != -1) {
  137. removeNextChar();
  138. done = true;
  139. }
  140. } else {
  141. String line = RubyPlugin.getActiveView().getLineUpToCaret();
  142. int startIndex = line.indexOf(start);
  143. if (startIndex != -1 && startIndex != (line.length() - 1)) {
  144. removeNextChar();
  145. done = true;
  146. }
  147. }
  148. }
  149. return done;
  150. }
  151. private void removeNextChar() {
  152. int position = textArea.getCaretPosition();
  153. Selection.Range range = new Selection.Range(position, position + 1);
  154. textArea.setSelection(range);
  155. textArea.setSelectedText("");
  156. }
  157. private char lastBehind() {
  158. int position = textArea.getCaretPosition();
  159. String text = textArea.getText();
  160. return position > 1 ? text.charAt(position - 2) : NIL_CHAR;
  161. }
  162. private char behind() {
  163. int position = textArea.getCaretPosition();
  164. String text = textArea.getText();
  165. return position > 0 ? text.charAt(position - 1) : NIL_CHAR;
  166. }
  167. private char ahead() {
  168. int position = textArea.getCaretPosition();
  169. String text = textArea.getText();
  170. return position < text.length() ? text.charAt(position) : NIL_CHAR;
  171. }
  172. private static char charLastBehind() {
  173. return CharCaretListener.getCharLastBehind();
  174. }
  175. private static char charBehind() {
  176. return CharCaretListener.getCharBehind();
  177. }
  178. private static char charAhead() {
  179. return CharCaretListener.getCharAhead();
  180. }
  181. private static boolean ignoreBackspace() {
  182. RubyToken token = CharCaretListener.getCurrentToken();
  183. return token.isComment() || (token.isLiteral() && !(charBehind() == '\n' || charBehind() == '\r'));
  184. }
  185. private static boolean ignoreCharacter() {
  186. RubyToken token = CharCaretListener.getCurrentToken();
  187. RubyToken lastToken = CharCaretListener.getLastToken();
  188. return token == null || token.isComment() || (token.isLiteral() && lastToken != null && lastToken.isLiteral());
  189. }
  190. private static boolean isCharacter(KeyEvent e) {
  191. return e != null && !Character.isWhitespace(e.getKeyChar());
  192. }
  193. private static boolean isBackspace(KeyEvent e) {
  194. return e != null && e.getKeyChar() == '\b' && e.getModifiers() == 0;
  195. }
  196. private boolean isRuby() {
  197. return RubyPlugin.isRuby(textArea);
  198. }
  199. }