From: <sh...@us...> - 2009-03-30 06:22:55
|
Revision: 14871 http://jedit.svn.sourceforge.net/jedit/?rev=14871&view=rev Author: shlomy Date: 2009-03-30 06:22:45 +0000 (Mon, 30 Mar 2009) Log Message: ----------- Initial attempt to use the SideKick completion pop-up for code completion. The code is now more or less copied from SideKick. This is the initial step in refactoring the SideKick completion pop-up to a generic completion pop-up that can be used by other plugins as well. Modified Paths: -------------- plugins/CtagsInterface/branches/ProjectViewerTrunk/src/ctagsinterface/jedit/TagCompletion.java plugins/CtagsInterface/branches/ProjectViewerTrunk/src/ctagsinterface/main/CtagsInterfacePlugin.java Added Paths: ----------- plugins/CtagsInterface/branches/ProjectViewerTrunk/src/ctagsinterface/jedit/EnhancedCompletion.java plugins/CtagsInterface/branches/ProjectViewerTrunk/src/ctagsinterface/jedit/EnhancedCompletionPopup.java Added: plugins/CtagsInterface/branches/ProjectViewerTrunk/src/ctagsinterface/jedit/EnhancedCompletion.java =================================================================== --- plugins/CtagsInterface/branches/ProjectViewerTrunk/src/ctagsinterface/jedit/EnhancedCompletion.java (rev 0) +++ plugins/CtagsInterface/branches/ProjectViewerTrunk/src/ctagsinterface/jedit/EnhancedCompletion.java 2009-03-30 06:22:45 UTC (rev 14871) @@ -0,0 +1,200 @@ +/* + * SideKickCompletion.java + * :tabSize=8:indentSize=8:noTabs=false: + * :folding=explicit:collapseFolds=1: + * + * Copyright (C) 2003, 2005 Slava Pestov + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package ctagsinterface.jedit; + +import javax.swing.*; +import java.util.*; + +import org.gjt.sp.jedit.*; +import org.gjt.sp.jedit.buffer.JEditBuffer; +import org.gjt.sp.jedit.textarea.*; + +/** + * A code completion instance.<p> + * + * This is a wrapper around a collection of possible completions, with callbacks + * for inserting and displaying the completions in a popup menu. + * + * @author Slava Pestov + * @version $Id: SideKickCompletion.java 10427 2007-08-22 22:43:15Z ezust $ + * @since SideKick 0.3 + */ +public class EnhancedCompletion +{ + public EnhancedCompletion(View view, String text) + { + this.view = view; + textArea = view.getTextArea(); + this.text = text; + } + + /** + * @param items - a list of strings containing the possible completions. + */ + public EnhancedCompletion(View view, String text, + List<Object> items) + { + this(view, text); + this.items = items; + } + + public EnhancedCompletion(View view, String text, Object[] items) + { + this(view, text); + this.items = Arrays.asList(items); + } + + public int size() + { + return items.size(); + } + + public Object get(int index) + { + return items.get(index); + } + + public String getCompletionDescription(int index) + { + return null; + } + + /** + * @return If this returns false, then we create a new completion + * object after user input. + */ + public boolean updateInPlace(EditPane editPane, int caret) + { + return false; + } + + public ListCellRenderer getRenderer() + { + return new DefaultListCellRenderer(); + } + + public void insert(int index) + { + String selected = String.valueOf(get(index)); + int caret = textArea.getCaretPosition(); + Selection s = textArea.getSelectionAtOffset(caret); + int start = (s == null ? caret : s.getStart()); + JEditBuffer buffer = textArea.getBuffer(); + try + { + buffer.beginCompoundEdit(); + buffer.remove(start - text.length(),text.length()); + buffer.insert(start - text.length(),selected); + } + finally + { + buffer.endCompoundEdit(); + } + } + + // The length of the text being completed (for popup positioning). + public int getTokenLength() + { + return text.length(); + } + + // Characters that accept the selected completion + protected String getAcceptChars() + { + return " \n\t"; + } + + // Characters that should be inserted after the completion + protected String getInsertChars() + { + return " "; + } + + /** + * @param selectedIndex The index of the selected completion. + * @param keyChar the character typed by the user. + * @return True if completion should continue, false otherwise. + */ + public boolean handleKeystroke(int selectedIndex, char keyChar) + { + if (getAcceptChars().indexOf(keyChar) > -1) + { + insert(selectedIndex); + if (getInsertChars().indexOf(keyChar) > -1) + textArea.userInput(keyChar); + return false; + } + else + { + textArea.userInput(keyChar); + return true; + } + } + + protected String getWordAtCaret(EditPane ep, int caret) + { + return null; + } + + /** + * Returns suitable completions for insertion at the specified + * position. + * + * Returns null by default. + * + * @param editPane The edit pane involved. + * @param caret The caret position. + */ + public EnhancedCompletion complete(EditPane editPane, int caret) + { + try { + String[] keywords = + editPane.getBuffer().getKeywordMapAtOffset( + caret).getKeywords(); + if (keywords.length > 0) { + String word = getWordAtCaret(editPane, caret); + if ((word != null) && (word.length() > 0)) { + List<String> possibles = new ArrayList<String>(); + for (int i = 0; i < keywords.length; i++) { + String kw = keywords[i]; + if (kw.startsWith(word) && (! kw.equals(word))) + possibles.add(keywords[i]); + } + Collections.sort(possibles); + List<Object> completions = new ArrayList<Object>( + possibles); + return new EnhancedCompletion(editPane.getView(), + word, completions); + } + } + } + catch (Exception e) { + } + return null; + } + + protected View view; + protected JEditTextArea textArea; + protected String text; + protected List<Object> items = new ArrayList<Object>(); +} Added: plugins/CtagsInterface/branches/ProjectViewerTrunk/src/ctagsinterface/jedit/EnhancedCompletionPopup.java =================================================================== --- plugins/CtagsInterface/branches/ProjectViewerTrunk/src/ctagsinterface/jedit/EnhancedCompletionPopup.java (rev 0) +++ plugins/CtagsInterface/branches/ProjectViewerTrunk/src/ctagsinterface/jedit/EnhancedCompletionPopup.java 2009-03-30 06:22:45 UTC (rev 14871) @@ -0,0 +1,175 @@ +package ctagsinterface.jedit; + +import java.awt.Component; +import java.awt.Point; +import java.awt.event.KeyEvent; + +import javax.swing.JList; +import javax.swing.ListCellRenderer; +import javax.swing.SwingUtilities; + +import org.gjt.sp.jedit.EditPane; +import org.gjt.sp.jedit.View; +import org.gjt.sp.jedit.gui.CompletionPopup; +import org.gjt.sp.jedit.textarea.JEditTextArea; +import org.gjt.sp.jedit.textarea.TextAreaPainter; + +@SuppressWarnings("serial") +public class EnhancedCompletionPopup extends CompletionPopup +{ + private View view; + private EnhancedCompletion complete; + + public EnhancedCompletionPopup(View view, int caret, + EnhancedCompletion complete, boolean active) + { + super(view, getLocation(view.getTextArea(), caret, complete)); + + this.view = view; + this.complete = complete; + + reset(new Candidates(), active); + } + + /// Inactive popup + public EnhancedCompletionPopup(View view, int caret, + EnhancedCompletion complete) + { + this(view, caret, complete, false); + } + + protected void keyPressed(KeyEvent evt) + { + // These code should be reduced to make this popup behave + // like a built-in popup. But these are here to keep + // compatibility with the old implementation before + // rafctoring out of CompletionPopup. + switch(evt.getKeyCode()) + { + case KeyEvent.VK_ENTER: + keyTyped('\n'); + evt.consume(); + break; + case KeyEvent.VK_TAB: + keyTyped('\t'); + evt.consume(); + break; + case KeyEvent.VK_SPACE: + evt.consume(); + break; + case KeyEvent.VK_BACK_SPACE: + if (!canHandleBackspace()) + dispose(); + break; + case KeyEvent.VK_DELETE: + dispose(); + break; + default: + break; + } + } + + protected boolean canHandleBackspace() + { + return false; + } + + public void keyTyped(KeyEvent evt) + { + char ch = evt.getKeyChar(); + if ((ch == '\b') && (! canHandleBackspace())) + { + evt.consume(); + return; + } + + keyTyped(ch); + + evt.consume(); + } + + private static Point getLocation(JEditTextArea textArea, + int caret, EnhancedCompletion complete) + { + Point location = textArea.offsetToXY(caret - + complete.getTokenLength()); + TextAreaPainter painter = textArea.getPainter(); + location.y += painter.getFontMetrics().getHeight(); + SwingUtilities.convertPointToScreen(location, painter); + return location; + } + + private class Candidates implements CompletionPopup.Candidates + { + private final ListCellRenderer renderer; + + public Candidates() + { + renderer = complete.getRenderer(); + } + + public int getSize() + { + return complete.size(); + } + + public boolean isValid() + { + return complete != null && complete.size() > 0; + } + + public void complete(int index) + { + complete.insert(index); + } + + public Component getCellRenderer(JList list, int index, + boolean isSelected, boolean cellHasFocus) + { + return renderer.getListCellRendererComponent(list, + complete.get(index), index, + isSelected, cellHasFocus); + } + + public String getDescription(int index) + { + return complete.getCompletionDescription(index); + } + } + + private void keyTyped(char ch) + { + // If no completion is selected, do not pass the key to + // handleKeystroke() method. This avoids interfering + // between a bit intermittent user typing and automatic + // completion (which is not selected initially). + int selected = getSelectedIndex(); + if (selected == -1) + { + view.getTextArea().userInput(ch); + updateCompletion(false); + } + else if (complete.handleKeystroke(selected, ch)) + updateCompletion(true); + else + dispose(); + } + + private void updateCompletion(boolean active) + { + EnhancedCompletion newComplete = complete; + EditPane editPane = view.getEditPane(); + JEditTextArea textArea = editPane.getTextArea(); + int caret = textArea.getCaretPosition(); + if (! newComplete.updateInPlace(editPane, caret)) + newComplete = complete.complete(editPane, caret); + if ((newComplete == null) || (newComplete.size() == 0)) + dispose(); + else + { + complete = newComplete; + setLocation(getLocation(textArea, caret, complete)); + reset(new Candidates(), active); + } + } +} Modified: plugins/CtagsInterface/branches/ProjectViewerTrunk/src/ctagsinterface/jedit/TagCompletion.java =================================================================== --- plugins/CtagsInterface/branches/ProjectViewerTrunk/src/ctagsinterface/jedit/TagCompletion.java 2009-03-30 06:04:09 UTC (rev 14870) +++ plugins/CtagsInterface/branches/ProjectViewerTrunk/src/ctagsinterface/jedit/TagCompletion.java 2009-03-30 06:22:45 UTC (rev 14871) @@ -4,9 +4,9 @@ import org.gjt.sp.jedit.Buffer; import org.gjt.sp.jedit.View; +import org.gjt.sp.jedit.textarea.JEditTextArea; import superabbrevs.SuperAbbrevs; - import ctagsinterface.db.Query; import ctagsinterface.db.TagDB; import ctagsinterface.main.CtagsInterfacePlugin; @@ -17,6 +17,33 @@ private View view; private String prefix; + public static void complete(View view, String prefix) + { + final TagCompletion completion = new TagCompletion(view, + prefix); + final Vector<Tag> tags = completion.getCompletions(); + if (tags == null || tags.isEmpty()) + return; + if (tags.size() > 1) + { + String [] completions = new String[tags.size()]; + for (int i = 0; i < tags.size(); i++) + completions[i] = completion.getCompletionString(tags.get(i)); + EnhancedCompletion options = new EnhancedCompletion( + view, prefix, completions) + { + public void insert(int index) { + completion.complete(tags.get(index)); + } + }; + JEditTextArea ta = view.getTextArea(); + new EnhancedCompletionPopup(view, ta.getCaretPosition(), + options, true); + } + else + completion.complete(tags.get(0)); + } + public TagCompletion(View view, String prefix) { this.view = view; @@ -91,4 +118,5 @@ String abbrev = createAbbrev(sig); SuperAbbrevs.expandAbbrev(view, abbrev, null); } + } Modified: plugins/CtagsInterface/branches/ProjectViewerTrunk/src/ctagsinterface/main/CtagsInterfacePlugin.java =================================================================== --- plugins/CtagsInterface/branches/ProjectViewerTrunk/src/ctagsinterface/main/CtagsInterfacePlugin.java 2009-03-30 06:04:09 UTC (rev 14870) +++ plugins/CtagsInterface/branches/ProjectViewerTrunk/src/ctagsinterface/main/CtagsInterfacePlugin.java 2009-03-30 06:22:45 UTC (rev 14871) @@ -297,29 +297,7 @@ String prefix = getCompletionPrefix(view); if (prefix == null) return; - TagCompletion completion = new TagCompletion(view, prefix); - Vector<Tag> tags = completion.getCompletions(); - if (tags == null || tags.isEmpty()) - return; - Tag tag = tags.get(0); - if (tags.size() > 1) - { - String [] completions = new String[tags.size()]; - for (int i = 0; i < tags.size(); i++) - completions[i] = completion.getCompletionString(tags.get(i)); - String sel = (String) JOptionPane.showInputDialog(view, - "Select completion", "Code completion dialog", - JOptionPane.QUESTION_MESSAGE, null, completions, - completions[0]); - if (sel == null) - return; - for (int i = 0; i < completions.length; i++) - if (sel == completions[i]) { - tag = tags.get(i); - break; - } - } - completion.complete(tag); + TagCompletion.complete(view, prefix); } // Actions: Offer code completion options This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |