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