This is an automated email from the git hooks/post-receive script.

ben pushed a commit to branch master
in repository autocomplete.

commit ff7db970571a3b5f306efd94bea5092198da5aeb
Author: bobbylight <[email protected]>
Date:   Sun Jun 17 17:33:03 2012 +0000

    Starting work on TemplateCompletions - allows completions for parameterized 
boilerplate code - for-loops, etc.
---
 .../fife/ui/autocomplete/FunctionCompletion.java   |   15 +-
 .../ui/autocomplete/ParameterizedCompletion.java   |   37 +-
 .../ParameterizedCompletionChoicesWindow.java      |    4 +
 .../ParameterizedCompletionDescriptionToolTip.java |  376 ++++++++++++++++----
 .../ParameterizedCompletionInsertionInfo.java      |   67 +++-
 src/org/fife/ui/autocomplete/SizeGrip.java         |    3 -
 .../fife/ui/autocomplete/TemplateCompletion.java   |  213 ++++++++---
 src/org/fife/ui/autocomplete/TemplatePiece.java    |   63 ++++
 8 files changed, 647 insertions(+), 131 deletions(-)

diff --git a/src/org/fife/ui/autocomplete/FunctionCompletion.java 
b/src/org/fife/ui/autocomplete/FunctionCompletion.java
index 9f9b13e..427d146 100644
--- a/src/org/fife/ui/autocomplete/FunctionCompletion.java
+++ b/src/org/fife/ui/autocomplete/FunctionCompletion.java
@@ -147,7 +147,8 @@ public class FunctionCompletion extends VariableCompletion
 
 
        public ParameterizedCompletionInsertionInfo getInsertionInfo(
-                       JTextComponent tc, boolean addParamStartList) {
+                       JTextComponent tc, boolean addParamStartList,
+                       boolean replaceTabsWithSpaces) {
 
                ParameterizedCompletionInsertionInfo info =
                        new ParameterizedCompletionInsertionInfo();
@@ -163,8 +164,10 @@ public class FunctionCompletion extends VariableCompletion
                // this tool tip.
                int minPos = dot;
                Position maxPos = null;
+               int defaultEndOffs = -1;
                try {
-                       maxPos = 
tc.getDocument().createPosition(dot-sb.length());
+                       maxPos = 
tc.getDocument().createPosition(dot-sb.length()+1);
+                       defaultEndOffs = dot-sb.length();
                } catch (BadLocationException ble) {
                        ble.printStackTrace(); // Never happens
                }
@@ -192,7 +195,13 @@ public class FunctionCompletion extends VariableCompletion
                        }
                }
                sb.append(getProvider().getParameterListEnd());
-
+               int endOffs = dot + sb.length();
+               if (addParamStartList) {
+                       endOffs -= 
1;//getProvider().getParameterListStart().length();
+               }
+               info.addReplacementLocation(endOffs, endOffs); // offset after 
function
+               info.setDefaultEndOffs(endOffs);
+               
                int selectionEnd = paramCount>0 ? (dot+firstParamLen) : dot;
                info.setInitialSelection(dot, selectionEnd);
                info.setTextToInsert(sb.toString());
diff --git a/src/org/fife/ui/autocomplete/ParameterizedCompletion.java 
b/src/org/fife/ui/autocomplete/ParameterizedCompletion.java
index 1d995f0..acd674f 100644
--- a/src/org/fife/ui/autocomplete/ParameterizedCompletion.java
+++ b/src/org/fife/ui/autocomplete/ParameterizedCompletion.java
@@ -50,7 +50,8 @@ public interface ParameterizedCompletion extends Completion {
 
 
        public ParameterizedCompletionInsertionInfo getInsertionInfo(
-                       JTextComponent tc, boolean addParamStartList);
+                       JTextComponent tc, boolean addParamStartList,
+                       boolean replaceTabsWithSpaces);
 
 
        /**
@@ -64,6 +65,7 @@ public interface ParameterizedCompletion extends Completion {
                private String name;
                private Object type;
                private String desc;
+               private boolean isEndParam;
 
                /**
                 * Constructor.
@@ -77,8 +79,30 @@ public interface ParameterizedCompletion extends Completion {
                 * @param name The name of the parameter.
                 */
                public Parameter(Object type, String name) {
+                       this(type, name, false);
+               }
+
+               /**
+                * Constructor.
+                *
+                * @param type The type of this parameter.  This may be
+                *        <code>null</code> for languages without specific 
types,
+                *        dynamic typing, etc.  Usually you'll pass a String 
for this
+                *        value, but you may pass any object representing a 
type in
+                *        your language, as long as its <code>toString()</code> 
method
+                *        returns a string representation of the type.
+                * @param name The name of the parameter.
+                * @param endParam Whether this parameter is an "ending 
parameter;"
+                *        that is, whether this parameter is at a logical 
"ending
+                *        point" in the completion text.  If the user types in a
+                *        parameter that is an ending point, parameter 
completion mode
+                *        terminates.  Set this to <code>true</code> for a 
trailing
+                *        parameter after a function call's closing ')', for 
example.
+                */
+               public Parameter(Object type, String name, boolean endParam) {
                        this.name = name;
                        this.type = type;
+                       this.isEndParam = endParam;
                }
 
                public String getDescription() {
@@ -107,6 +131,17 @@ public interface ParameterizedCompletion extends 
Completion {
                        return type;
                }
 
+               /**
+                * @return Whether this parameter is an "ending parameter;"
+                *         that is, whether this parameter is at a logical 
"ending
+                *         point" in the completion text.  If the user types in 
a
+                *         parameter that is an ending point, parameter 
completion mode
+                *         terminates.
+                */
+               public boolean isEndParam() {
+                       return isEndParam;
+               }
+
                public void setDescription(String desc) {
                        this.desc = desc;
                }
diff --git 
a/src/org/fife/ui/autocomplete/ParameterizedCompletionChoicesWindow.java 
b/src/org/fife/ui/autocomplete/ParameterizedCompletionChoicesWindow.java
index cd553cf..31f21e8 100644
--- a/src/org/fife/ui/autocomplete/ParameterizedCompletionChoicesWindow.java
+++ b/src/org/fife/ui/autocomplete/ParameterizedCompletionChoicesWindow.java
@@ -280,6 +280,10 @@ public class ParameterizedCompletionChoicesWindow extends 
JWindow {
 
                }
 
+               else {
+                       setVisible(false);
+               }
+
        }
 
 
diff --git 
a/src/org/fife/ui/autocomplete/ParameterizedCompletionDescriptionToolTip.java 
b/src/org/fife/ui/autocomplete/ParameterizedCompletionDescriptionToolTip.java
index 677c2f7..47a1e48 100644
--- 
a/src/org/fife/ui/autocomplete/ParameterizedCompletionDescriptionToolTip.java
+++ 
b/src/org/fife/ui/autocomplete/ParameterizedCompletionDescriptionToolTip.java
@@ -20,6 +20,7 @@ import java.awt.event.FocusListener;
 import java.awt.event.InputEvent;
 import java.awt.event.KeyEvent;
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 import javax.swing.AbstractAction;
 import javax.swing.Action;
@@ -34,6 +35,9 @@ import javax.swing.SwingUtilities;
 import javax.swing.UIManager;
 import javax.swing.event.CaretEvent;
 import javax.swing.event.CaretListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.text.AbstractDocument;
 import javax.swing.text.BadLocationException;
 import javax.swing.text.Document;
 import javax.swing.text.Highlighter;
@@ -41,7 +45,13 @@ import javax.swing.text.JTextComponent;
 import javax.swing.text.Position;
 import javax.swing.text.Highlighter.Highlight;
 
+import org.fife.ui.autocomplete.ParameterizedCompletion.Parameter;
+import 
org.fife.ui.autocomplete.ParameterizedCompletionInsertionInfo.ReplacementCopy;
+import org.fife.ui.rsyntaxtextarea.DocumentRange;
 import org.fife.ui.rsyntaxtextarea.PopupWindowDecorator;
+import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
+import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities;
+import org.fife.ui.rtextarea.ChangeableHighlightPainter;
 
 
 /**
@@ -63,11 +73,17 @@ class ParameterizedCompletionDescriptionToolTip {
         */
        Highlighter.HighlightPainter p;
 
+       Highlighter.HighlightPainter paramCopyP;
+
        /**
         * The tags for the highlights around parameters.
         */
        List tags;
 
+       private List paramCopyInfos;
+
+       private transient boolean ignoringDocumentEvents;
+
        /**
         * The parent AutoCompletion instance.
         */
@@ -100,6 +116,8 @@ class ParameterizedCompletionDescriptionToolTip {
         */
        private Position maxPos; // Moves with text inserted.
 
+       private Position defaultEndOffs;
+
        /**
         * A small popup window giving likely choices for parameterized 
completions.
         */
@@ -158,7 +176,7 @@ class ParameterizedCompletionDescriptionToolTip {
 
                descLabel = new JLabel();
                descLabel.setBorder(BorderFactory.createCompoundBorder(
-                                       
BorderFactory.createLineBorder(Color.BLACK),
+                                       TipUtil.getToolTipBorder(),
                                        BorderFactory.createEmptyBorder(2, 5, 
2, 5)));
                descLabel.setOpaque(true);
                descLabel.setBackground(TipUtil.getToolTipBackground());
@@ -185,7 +203,9 @@ class ParameterizedCompletionDescriptionToolTip {
                listener = new Listener();
 
                p = new OutlineHighlightPainter(Color.GRAY);
+               paramCopyP = new ChangeableHighlightPainter(new Color(255, 224, 
224));
                tags = new ArrayList(1); // Usually small
+               paramCopyInfos = new ArrayList(1);
 
                paramChoicesWindow = createParamChoicesWindow();
 
@@ -206,6 +226,31 @@ class ParameterizedCompletionDescriptionToolTip {
        }
 
 
+       public String getArgumentText(int offs) {
+               List paramHighlights = getParameterHighlights();
+               if (paramHighlights==null || paramHighlights.size()==0) {
+                       return null;
+               }
+               for (int i=0; i<paramHighlights.size(); i++) {
+                       Highlight h = (Highlight)paramHighlights.get(i);
+                       if (offs>=h.getStartOffset() && offs<=h.getEndOffset()) 
{
+                               int start = h.getStartOffset() + 1;
+                               int len = h.getEndOffset() - start;
+                               JTextComponent tc = ac.getTextComponent();
+                               Document doc = tc.getDocument();
+                               try {
+                                       return doc.getText(start, len);
+                               } catch (BadLocationException ble) {
+                                       
UIManager.getLookAndFeel().provideErrorFeedback(tc);
+                                       ble.printStackTrace();
+                                       return null;
+                               }
+                       }
+               }
+               return null;
+       }
+
+
        /**
         * Returns the highlight of the current parameter.
         *
@@ -234,6 +279,27 @@ class ParameterizedCompletionDescriptionToolTip {
        }
 
 
+       private int getCurrentParameterIndex() {
+
+               JTextComponent tc = ac.getTextComponent();
+               int dot = tc.getCaretPosition();
+               if (dot>0) {
+                       dot--; // Workaround for Java Highlight issues
+               }
+
+               List paramHighlights = getParameterHighlights();
+               for (int i=0; i<paramHighlights.size(); i++) {
+                       Highlight h = (Highlight)paramHighlights.get(i);
+                       if (dot>=h.getStartOffset() && dot<h.getEndOffset()) {
+                               return i;
+                       }
+               }
+
+               return -1;
+
+       }
+
+
        /**
         * Returns the starting offset of the current parameter.
         *
@@ -247,6 +313,54 @@ class ParameterizedCompletionDescriptionToolTip {
        }
 
 
+       /**
+        * Returns the highlight from a list that comes "first" in a list.  Even
+        * though most parameter highlights are ordered, sometimes they aren't
+        * (e.g. the "cursor" parameter in a template completion is always last,
+        * even though it can be anywhere in the template).
+        *
+        * @param highlights The list of highlights.  Assumed to be non-empty.
+        * @return The highlight that comes first in the document.
+        * @see #getLastHighlight(List)
+        */
+       private static final int getFirstHighlight(List highlights) {
+               int first = -1;
+               Highlight firstH = null;
+               for (int i=0; i<highlights.size(); i++) {
+                       Highlight h = (Highlight)highlights.get(i);
+                       if (firstH==null || 
h.getStartOffset()<firstH.getStartOffset()) {
+                               firstH = h;
+                               first = i;
+                       }
+               }
+               return first;
+       }
+
+
+       /**
+        * Returns the highlight from a list that comes "last" in that list.  
Even
+        * though most parameter highlights are ordered, sometimes they aren't
+        * (e.g. the "cursor" parameter in a template completion is always last,
+        * even though it can be anywhere in the template.
+        *
+        * @param highlights The list of highlights.  Assumed to be non-empty.
+        * @return The highlight that comes last in the document.
+        * @see #getFirstHighlight(List)
+        */
+       private static final int getLastHighlight(List highlights) {
+               int last = -1;
+               Highlight lastH = null;
+               for (int i=highlights.size()-1; i>=0; i--) {
+                       Highlight h = (Highlight)highlights.get(i);
+                       if (lastH==null || 
h.getStartOffset()>lastH.getStartOffset()) {
+                               lastH = h;
+                               last = i;
+                       }
+               }
+               return last;
+       }
+
+
        private List getParameterHighlights() {
                List paramHighlights = new ArrayList(1);
                JTextComponent tc = ac.getTextComponent();
@@ -360,7 +474,6 @@ class ParameterizedCompletionDescriptionToolTip {
 
                JTextComponent tc = ac.getTextComponent();
                int dot = tc.getCaretPosition();
-
                int tagCount = tags.size();
                if (tagCount==0) {
                        tc.setCaretPosition(maxPos.getOffset());
@@ -383,17 +496,18 @@ class ParameterizedCompletionDescriptionToolTip {
                        }
                }
 
-               if (currentNext!=null && dot<=currentNext.getStartOffset()) {
-                        // "+1" is a workaround for Java Highlight issues.
-                       tc.setSelectionStart(currentNext.getStartOffset()+1);
-                       tc.setSelectionEnd(currentNext.getEndOffset());
-                       updateText(pos);
-               }
-               else {
-                       tc.setCaretPosition(maxPos.getOffset());
-                       setVisible(false, false);
+               // No params after caret - go to first one
+               if (currentNext.getStartOffset()+1<=dot) {
+                       int nextIndex = getFirstHighlight(highlights);
+                       currentNext = (Highlight)highlights.get(nextIndex);
+                       pos = 0;
                }
 
+               // "+1" is a workaround for Java Highlight issues.
+               tc.setSelectionStart(currentNext.getStartOffset()+1);
+               tc.setSelectionEnd(currentNext.getEndOffset());
+               updateText(pos);
+
        }
 
 
@@ -422,15 +536,18 @@ class ParameterizedCompletionDescriptionToolTip {
                        Highlight h = (Highlight)highlights.get(i);
                        if (currentPrev==null || 
currentPrev.getStartOffset()>=dot ||
                                        (h.getStartOffset()<selStart &&
-                                       
h.getStartOffset()>currentPrev.getStartOffset())) {
+                                       
(h.getStartOffset()>currentPrev.getStartOffset() ||
+                                                       
pos==lastSelectedParam))) {
                                currentPrev = h;
                                pos = i;
                        }
                }
 
                // Loop back from param 0 to last param.
-               if (pos==0 && lastSelectedParam==0 && highlights.size()>1) {
-                       pos = highlights.size() - 1;
+               int firstIndex = getFirstHighlight(highlights);
+               //if (pos==0 && lastSelectedParam==0 && highlights.size()>1) {
+               if (pos==firstIndex && lastSelectedParam==firstIndex && 
highlights.size()>1) {
+                       pos = getLastHighlight(highlights);
                        currentPrev = (Highlight)highlights.get(pos);
                         // "+1" is a workaround for Java Highlight issues.
                        tc.setSelectionStart(currentPrev.getStartOffset()+1);
@@ -451,6 +568,49 @@ class ParameterizedCompletionDescriptionToolTip {
        }
 
 
+       private void possiblyUpdateParamCopies(Document doc) {
+               
+               int index = getCurrentParameterIndex();
+               // FunctionCompletions add an extra param at end of inserted 
text
+               if (index>-1 && index<pc.getParamCount()) {
+
+                       // Typing in an "end parameter" => stop parameter 
assistance.
+                       Parameter param = pc.getParam(index);
+                       if (param.isEndParam()) {
+                               setVisible(false, false);
+                               return;
+                       }
+
+                       // Get the current value of the current parameter.
+                       List paramHighlights = getParameterHighlights();
+                       Highlight h = (Highlight)paramHighlights.get(index);
+                       int start = h.getStartOffset() + 1; // param offsets 
are offset (!) by 1
+                       int len = h.getEndOffset() - start;
+                       String replacement = null;
+                       try {
+                               replacement = doc.getText(start, len);
+                       } catch (BadLocationException ble) {
+                               ble.printStackTrace(); // Never happens
+                       }
+
+                       // Replace any param copies tracking this parameter 
with the
+                       // value of this parameter.
+                       for (Iterator i=paramCopyInfos.iterator(); i.hasNext(); 
) {
+                               ParamCopyInfo pci = (ParamCopyInfo)i.next();
+                               if (pci.paramName.equals(param.getName())) {
+                                       pci.h = replaceHighlightedText(doc, 
pci.h, replacement);
+                               }
+                       }
+
+               }
+
+               else { // Probably the "end parameter" for FunctionCompletions.
+                       setVisible(false, false);
+               }
+
+       }
+
+
        /**
         * Updates the optional window listing likely completion choices,
         */
@@ -496,6 +656,52 @@ class ParameterizedCompletionDescriptionToolTip {
                        h.removeHighlight(tags.get(i));
                }
                tags.clear();
+               for (int i=0; i<paramCopyInfos.size(); i++) {
+                       ParamCopyInfo pci = 
(ParamCopyInfo)paramCopyInfos.get(i);
+                       h.removeHighlight(pci.h);
+               }
+               paramCopyInfos.clear();
+       }
+
+
+       /**
+        * Replaces highlighted text with new text.  Takes special care so that
+        * the highlight stays just around the newly-highlighted text, since
+        * Swing's <code>Highlight</code> classes are funny about insertions at
+        * their start offsets.
+        *
+        * @param doc The document.
+        * @param h The highlight whose text to change.
+        * @param replacement The new text to be in the highlight.
+        * @return The replacement highlight for <code>h</code>.
+        */
+       private Highlight replaceHighlightedText(Document doc, Highlight h,
+                                                                       String 
replacement) {
+               try {
+
+                       int start = h.getStartOffset();
+                       int len = h.getEndOffset() - start;
+                       Highlighter highlighter = 
ac.getTextComponent().getHighlighter();
+                       highlighter.removeHighlight(h);
+
+                       if (doc instanceof AbstractDocument) {
+                               ((AbstractDocument)doc).replace(start, len, 
replacement, null);
+                       }
+                       else {
+                               doc.remove(start, len);
+                               doc.insertString(start, replacement, null);
+                       }
+
+                       int newEnd = start + replacement.length();
+                       h = (Highlight)highlighter.addHighlight(start, newEnd, 
paramCopyP);
+                       return h;
+
+               } catch (BadLocationException ble) {
+                       ble.printStackTrace(); // Never happens
+               }
+
+               return null;
+
        }
 
 
@@ -693,28 +899,7 @@ class ParameterizedCompletionDescriptionToolTip {
                        // (such as type parameters in Java).  We need to take 
care to
                        // escape these.
                        String temp = pc.getParam(i).toString();
-                       int lt = temp.indexOf('<');
-                       if (lt>-1) {
-                               sb.append(temp.substring(0, lt));
-                               sb.append("&lt;");
-                               for (int j=lt+1; j<temp.length(); j++) {
-                                       char ch = temp.charAt(j);
-                                       switch (ch) {
-                                               case '<':
-                                                       sb.append("&lt;");
-                                                       break;
-                                               case '>':
-                                                       sb.append("&gt;");
-                                                       break;
-                                               default:
-                                                       sb.append(ch);
-                                                       break;
-                                       }
-                               }
-                       }
-                       else {
-                               sb.append(temp);
-                       }
+                       sb.append(RSyntaxUtilities.escapeForHtml(temp, "<br>", 
false));
 
                        if (i==selectedParam) {
                                sb.append("</b>");
@@ -775,7 +960,7 @@ class ParameterizedCompletionDescriptionToolTip {
 
                        // Otherwise, just move to the end.
                        JTextComponent tc = ac.getTextComponent();
-                       tc.setCaretPosition(maxPos.getOffset());
+                       tc.setCaretPosition(defaultEndOffs.getOffset());
                        setVisible(false, false);
 
                }
@@ -799,9 +984,9 @@ class ParameterizedCompletionDescriptionToolTip {
                        char end = pc.getProvider().getParameterListEnd();
 
                        // Are they at or past the end of the parameters?
-                       if (dot>=maxPos.getOffset()-1) { // ">=" for overwrite 
mode
+                       if (dot>=maxPos.getOffset()-2) { // ">=" for overwrite 
mode
 
-                               if (dot==maxPos.getOffset()) { // Happens in 
overwrite mode
+                               if (dot==maxPos.getOffset()-1) { // Happens in 
overwrite mode
                                        
tc.replaceSelection(Character.toString(end));
                                }
 
@@ -818,7 +1003,8 @@ class ParameterizedCompletionDescriptionToolTip {
                                                        return;
                                                }
                                        }
-                                       tc.setCaretPosition(maxPos.getOffset());
+                                       
//tc.setCaretPosition(maxPos.getOffset());
+                                       
tc.setCaretPosition(tc.getCaretPosition()+1);
                                }
 
                                setVisible(false, false);
@@ -832,30 +1018,6 @@ class ParameterizedCompletionDescriptionToolTip {
 
                }
 
-               public String getArgumentText(int offs) {
-                       List paramHighlights = getParameterHighlights();
-                       if (paramHighlights==null || paramHighlights.size()==0) 
{
-                               return null;
-                       }
-                       for (int i=0; i<paramHighlights.size(); i++) {
-                               Highlight h = (Highlight)paramHighlights.get(i);
-                               if (offs>=h.getStartOffset() && 
offs<=h.getEndOffset()) {
-                                       int start = h.getStartOffset() + 1;
-                                       int len = h.getEndOffset() - start;
-                                       JTextComponent tc = 
ac.getTextComponent();
-                                       Document doc = tc.getDocument();
-                                       try {
-                                               return doc.getText(start, len);
-                                       } catch (BadLocationException ble) {
-                                               
UIManager.getLookAndFeel().provideErrorFeedback(tc);
-                                               ble.printStackTrace();
-                                               return null;
-                                       }
-                               }
-                       }
-                       return null;
-               }
-
                public int getCount(String text, char ch) {
                        int count = 0;
                        int old = 0;
@@ -903,7 +1065,10 @@ class ParameterizedCompletionDescriptionToolTip {
         * @author Robert Futrell
         * @version 1.0
         */
-       private class Listener implements FocusListener, CaretListener {
+       private class Listener implements FocusListener, CaretListener,
+                                                       DocumentListener {
+
+               private boolean markOccurrencesEnabled;
 
                /**
                 * Called when the text component's caret moves.
@@ -917,6 +1082,7 @@ class ParameterizedCompletionDescriptionToolTip {
                        }
                        int dot = e.getDot();
                        if (dot<minPos || dot>=maxPos.getOffset()) {
+                               System.err.println(">>>>> dot==" + dot + ", " + 
minPos + ", " + maxPos);
                                setVisible(false, false);
                                return;
                        }
@@ -927,6 +1093,10 @@ class ParameterizedCompletionDescriptionToolTip {
                }
 
 
+               public void changedUpdate(DocumentEvent e) {
+               }
+
+
                /**
                 * Called when the text component gains focus.
                 *
@@ -947,6 +1117,24 @@ class ParameterizedCompletionDescriptionToolTip {
                }
 
 
+               private void handleDocumentEvent(final DocumentEvent e) {
+                       if (!ignoringDocumentEvents) {
+                               ignoringDocumentEvents = true;
+                               SwingUtilities.invokeLater(new Runnable() {
+                                       public void run() {
+                                               
possiblyUpdateParamCopies(e.getDocument());
+                                               ignoringDocumentEvents = false;
+                                       }
+                               });
+                       }
+               }
+
+
+               public void insertUpdate(DocumentEvent e) {
+                       handleDocumentEvent(e);
+               }
+
+
                /**
                 * Installs this listener onto a text component.
                 *
@@ -963,20 +1151,34 @@ class ParameterizedCompletionDescriptionToolTip {
                        tc.addFocusListener(this);
                        installKeyBindings();
 
+                       boolean replaceTabs = false;
+                       if (tc instanceof RSyntaxTextArea) {
+                               RSyntaxTextArea textArea = (RSyntaxTextArea)tc;
+                               markOccurrencesEnabled = 
textArea.getMarkOccurrences();
+                               textArea.setMarkOccurrences(false);
+                               replaceTabs = textArea.getTabsEmulated();
+                       }
+
                        Highlighter h = tc.getHighlighter();
 
                        try {
 
+                               // Insert the parameter text
                                ParameterizedCompletionInsertionInfo info =
-                                                               
pc.getInsertionInfo(tc, addParamStartList);
-
-                               // Insert the parameter text and add highlights 
around the
-                               // parameters.
+                                       pc.getInsertionInfo(tc, 
addParamStartList, replaceTabs);
                                tc.replaceSelection(info.getTextToInsert());
+
+                               // Add highlights around the parameters.
                                for (int i=0; i<info.getReplacementCount(); 
i++) {
-                                       Point pt = 
info.getReplacementLocation(i);
+                                       DocumentRange dr = 
info.getReplacementLocation(i);
                                         // "-1" is a workaround for Java 
Highlight issues.
-                                       tags.add(h.addHighlight(pt.x-1, pt.y, 
p));
+                                       
tags.add(h.addHighlight(dr.getStartOffset()-1, dr.getEndOffset(), p));
+                               }
+                               for (int i=0; i<info.getReplacementCopyCount(); 
i++) {
+                                       ReplacementCopy rc = 
info.getReplacementCopy(i);
+                                       paramCopyInfos.add(new 
ParamCopyInfo(rc.getId(),
+                                               
(Highlight)h.addHighlight(rc.getStart(), rc.getEnd(),
+                                                               paramCopyP)));
                                }
 
                                // Go back and start at the first parameter.
@@ -987,6 +1189,15 @@ class ParameterizedCompletionDescriptionToolTip {
 
                                minPos = info.getMinOffset();
                                maxPos = info.getMaxOffset();
+                               try {
+                                       defaultEndOffs = 
tc.getDocument().createPosition(
+                                                       
info.getDefaultEndOffs());
+                               } catch (BadLocationException ble) {
+                                       ble.printStackTrace(); // Never happens
+                               }
+
+                               // Listen for document events AFTER we insert
+                               tc.getDocument().addDocumentListener(this);
 
                        } catch (BadLocationException ble) {
                                ble.printStackTrace(); // Never happens
@@ -995,6 +1206,11 @@ class ParameterizedCompletionDescriptionToolTip {
                }
 
 
+               public void removeUpdate(DocumentEvent e) {
+                       handleDocumentEvent(e);
+               }
+
+
                /**
                 * Uninstalls this listener from the current text component.
                 * 
@@ -1004,8 +1220,13 @@ class ParameterizedCompletionDescriptionToolTip {
                        JTextComponent tc = ac.getTextComponent();
                        tc.removeCaretListener(this);
                        tc.removeFocusListener(this);
+                       tc.getDocument().removeDocumentListener(this);
                        uninstallKeyBindings();
 
+                       if (markOccurrencesEnabled) {
+                               
((RSyntaxTextArea)tc).setMarkOccurrences(markOccurrencesEnabled);
+                       }
+
                        // Remove WeakReferences in javax.swing.text.
                        maxPos = null;
                        minPos = -1;
@@ -1064,6 +1285,19 @@ class ParameterizedCompletionDescriptionToolTip {
        }
 
 
+       private static class ParamCopyInfo {
+
+               private String paramName;
+               private Highlight h;
+
+               public ParamCopyInfo(String paramName, Highlight h) {
+                       this.paramName = paramName;
+                       this.h = h;
+               }
+
+       }
+
+
        /**
         * Action performed when the user hits shift+tab.
         *
diff --git 
a/src/org/fife/ui/autocomplete/ParameterizedCompletionInsertionInfo.java 
b/src/org/fife/ui/autocomplete/ParameterizedCompletionInsertionInfo.java
index b82430d..f7e3a94 100644
--- a/src/org/fife/ui/autocomplete/ParameterizedCompletionInsertionInfo.java
+++ b/src/org/fife/ui/autocomplete/ParameterizedCompletionInsertionInfo.java
@@ -9,11 +9,12 @@
  */
 package org.fife.ui.autocomplete;
 
-import java.awt.Point;
 import java.util.ArrayList;
 import java.util.List;
 import javax.swing.text.Position;
 
+import org.fife.ui.rsyntaxtextarea.DocumentRange;
+
 
 /**
  * Describes a parameterized completion - what's being inserted, where the
@@ -26,13 +27,24 @@ class ParameterizedCompletionInsertionInfo {
 
        private int minOffs;
        private Position maxOffs;
+       private int defaultEnd;
        private int selStart;
        private int selEnd;
        private String textToInsert;
        private List replacementLocations;
+       private List replacementCopies;
 
 
        public ParameterizedCompletionInsertionInfo() {
+               defaultEnd = -1;
+       }
+
+
+       public void addReplacementCopy(String id, int start, int end) {
+               if (replacementCopies==null) {
+                       replacementCopies = new ArrayList(1);
+               }
+               replacementCopies.add(new ReplacementCopy(id, start, end));
        }
 
 
@@ -49,7 +61,12 @@ class ParameterizedCompletionInsertionInfo {
                if (replacementLocations==null) {
                        replacementLocations = new ArrayList(1);
                }
-               replacementLocations.add(new Point(start, end));
+               replacementLocations.add(new DocumentRange(start, end));
+       }
+
+
+       public int getDefaultEndOffs() {
+               return defaultEnd>-1 ? defaultEnd : getMaxOffset().getOffset();
        }
 
 
@@ -77,6 +94,11 @@ class ParameterizedCompletionInsertionInfo {
        }
 
 
+       public int getReplacementCopyCount() {
+               return replacementCopies==null ? 0 : replacementCopies.size();
+       }
+
+
        /**
         * Returns the number of replacements in the completion.
         *
@@ -87,6 +109,11 @@ class ParameterizedCompletionInsertionInfo {
        }
 
 
+       public ReplacementCopy getReplacementCopy(int index) {
+               return (ReplacementCopy)replacementCopies.get(index);
+       }
+
+
        /**
         * Returns the starting- and ending-offsets of the replacement regions
         * in the completion.
@@ -95,8 +122,8 @@ class ParameterizedCompletionInsertionInfo {
         * @return The range in the document of that replacement region.
         * @see #getReplacementCount()
         */
-       public Point getReplacementLocation(int index) {
-               return (Point)replacementLocations.get(index);
+       public DocumentRange getReplacementLocation(int index) {
+               return (DocumentRange)replacementLocations.get(index);
        }
 
 
@@ -178,6 +205,11 @@ class ParameterizedCompletionInsertionInfo {
        }
 
 
+       public void setDefaultEndOffs(int end) {
+               defaultEnd = end;
+       }
+
+
        /**
         * Sets the text to insert for the completion.
         *
@@ -189,4 +221,31 @@ class ParameterizedCompletionInsertionInfo {
        }
 
 
+       public static class ReplacementCopy {
+
+               private String id;
+               private int start;
+               private int end;
+
+               public ReplacementCopy(String id, int start, int end) {
+                       this.id = id;
+                       this.start = start;
+                       this.end = end;
+               }
+
+               public int getEnd() {
+                       return end;
+               }
+
+               public String getId() {
+                       return id;
+               }
+
+               public int getStart() {
+                       return start;
+               }
+
+       }
+
+
 }
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/SizeGrip.java 
b/src/org/fife/ui/autocomplete/SizeGrip.java
index e698cc8..3f90b84 100644
--- a/src/org/fife/ui/autocomplete/SizeGrip.java
+++ b/src/org/fife/ui/autocomplete/SizeGrip.java
@@ -193,9 +193,6 @@ class SizeGrip extends JPanel {
        /**
         * Listens for mouse events on this panel and resizes the parent window
         * appropriately.
-        *
-        * @author Robert Futrell
-        * @version 1.0
         */
        /*
         * NOTE: We use SwingUtilities.convertPointToScreen() instead of just 
using
diff --git a/src/org/fife/ui/autocomplete/TemplateCompletion.java 
b/src/org/fife/ui/autocomplete/TemplateCompletion.java
index 19a085c..6e5efad 100644
--- a/src/org/fife/ui/autocomplete/TemplateCompletion.java
+++ b/src/org/fife/ui/autocomplete/TemplateCompletion.java
@@ -15,8 +15,11 @@ import java.util.List;
 import javax.swing.text.BadLocationException;
 import javax.swing.text.Document;
 import javax.swing.text.JTextComponent;
+import javax.swing.text.PlainDocument;
 import javax.swing.text.Position;
 
+import org.fife.ui.autocomplete.TemplatePiece.Param;
+import org.fife.ui.autocomplete.TemplatePiece.ParamCopy;
 import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities;
 
 
@@ -25,7 +28,26 @@ import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities;
  * can tab through and fill in.  This completion type is useful for inserting
  * common boilerplate code, such as for-loops.<p>
  *
- * This class is a work in progress and currently should not be used.
+ * The format of a template is similar to those in Eclipse.  The following
+ * example would be the format for a for-loop template:
+ * 
+ * <pre>
+ * for (int ${i} = 0; ${i} &lt; ${array}.length; ${i}++) {
+ *    ${cursor}
+ * }
+ * </pre>
+ *
+ * In the above example, the first <code>${i}</code> is a parameter for the
+ * user to type into; all the other <code>${i}</code> instances are
+ * automatically changed to what the user types in the first one.  The 
parameter
+ * named <code>${cursor}</code> is the "ending position" of the template.  It's
+ * where the caret moves after it cycles through all other parameters.  If the
+ * user types into it, template mode terminates.  If more than one
+ * <code>${cursor}</code> parameter is specified, behavior is undefined.<p>
+ * 
+ * Leading whitespace is automatically added to lines if the template spans
+ * more than one line, and if used with a text component using a
+ * <code>PlainDocument</code>, tabs will be converted to spaces if requested.
  *
  * @author Robert Futrell
  * @version 1.0
@@ -35,7 +57,7 @@ public class TemplateCompletion extends AbstractCompletion
 
        private List pieces;
 
-       private String replacementText;
+       private String inputText;
 
        private String definitionString;
 
@@ -45,43 +67,35 @@ public class TemplateCompletion extends AbstractCompletion
        private List params;
 
 
-
-       public TemplateCompletion(CompletionProvider provider, String 
replacementText,
-                       String definitionString) {
+       public TemplateCompletion(CompletionProvider provider,
+                               String inputText, String definitionString, 
String template) {
                super(provider);
-               this.replacementText = replacementText;
+               this.inputText = inputText;
                this.definitionString = definitionString;
                pieces = new ArrayList(3);
                params = new ArrayList(3);
+               parse(template);
        }
 
 
-       public void addTemplatePiece(TemplatePiece piece) {
+       private void addTemplatePiece(TemplatePiece piece) {
                pieces.add(piece);
-               if (piece.isParam) {
+               if (piece instanceof Param && 
!"cursor".equals(piece.getText())) {
                        final String type = null; // TODO
-                       Parameter param = new Parameter(type, piece.text);
+                       Parameter param = new Parameter(type, piece.getText());
                        params.add(param);
                }
        }
 
 
+       public String getInputText() {
+               return inputText;
+       }
+
+
        private String getPieceText(int index, String leadingWS) {
-               String text = null;
                TemplatePiece piece = (TemplatePiece)pieces.get(index);
-               if (piece.id!=null) {
-                       final String id = piece.id;
-                       for (int i=0; i<pieces.size(); i++) {
-                               piece = (TemplatePiece)pieces.get(i);
-                               if (id.equals(piece.id)) {
-                                       text = piece.text;
-                                       break;
-                               }
-                       }
-               }
-               else {
-                       text = piece.text;
-               }
+               String text = piece.getText();
                if (text.indexOf('\n')>-1) {
                        text = text.replaceAll("\n", "\n" + leadingWS);
                }
@@ -90,13 +104,13 @@ public class TemplateCompletion extends AbstractCompletion
 
 
        /**
-        * For template completions, the "replacement text" is really just the
-        * first piece of the template, not the entire thing.  You should add
-        * template pieces so that the rest of the template is dynamically
-        * generated.
+        * Returns <code>null</code>; template completions insert all of their
+        * text via <code>getInsertionInfo()</code>.
+        *
+        * @return <code>null</code> always.
         */
        public String getReplacementText() {
-               return replacementText;
+               return null;
        }
 
 
@@ -112,19 +126,20 @@ public class TemplateCompletion extends AbstractCompletion
 
 
        public ParameterizedCompletionInsertionInfo getInsertionInfo(
-                       JTextComponent tc, boolean addParamStartList) {
+                       JTextComponent tc, boolean addParamStartList,
+                       boolean replaceTabsWithSpaces) {
 
                ParameterizedCompletionInsertionInfo info =
                        new ParameterizedCompletionInsertionInfo();
 
                StringBuffer sb = new StringBuffer();
                int dot = tc.getCaretPosition();
-               int paramCount = getParamCount();
 
                // Get the range in which the caret can move before we hide
                // this tool tip.
                int minPos = dot;
                Position maxPos = null;
+               int defaultEndOffs = -1;
                try {
                        maxPos = tc.getDocument().createPosition(dot);
                } catch (BadLocationException ble) {
@@ -132,6 +147,8 @@ public class TemplateCompletion extends AbstractCompletion
                }
                info.setCaretRange(minPos, maxPos);
                int firstParamLen = 0;
+               int selStart = dot; // Default value
+               int selEnd = selStart;
 
                Document doc = tc.getDocument();
                String leadingWS = null;
@@ -148,19 +165,38 @@ public class TemplateCompletion extends AbstractCompletion
                for (int i=0; i<pieces.size(); i++) {
                        TemplatePiece piece = (TemplatePiece)pieces.get(i);
                        String text = getPieceText(i, leadingWS);
-                       sb.append(text);
-                       int end = start + text.length();
-                       if (piece.isParam) {
-                               info.addReplacementLocation(start, end);
-                               if (firstParamLen==0) {
-                                       firstParamLen = text.length();
+                       if (piece instanceof Param && "cursor".equals(text)) {
+                               if (replaceTabsWithSpaces) {
+                                       start = 
possiblyReplaceTabsWithSpaces(sb, tc, start);
                                }
+                               defaultEndOffs = start;
+                       }
+                       else {
+                               int end = start + text.length();
+                               sb.append(text);
+                               if (piece instanceof Param) {
+                                       info.addReplacementLocation(start, end);
+                                       if (firstParamLen==0) {
+                                               firstParamLen = text.length();
+                                               selStart = start;
+                                               selEnd = selStart + 
firstParamLen;
+                                       }
+                               }
+                               else if (piece instanceof ParamCopy) {
+                                       
info.addReplacementCopy(piece.getText(), start, end);
+                               }
+                               start = end;
                        }
-                       start = end;
                }
-               int selectionEnd = paramCount>0 ? (dot+firstParamLen) : dot;
-               info.setInitialSelection(dot, selectionEnd);
+
+               info.setInitialSelection(selStart, selEnd);
+               if (defaultEndOffs>-1) {
+                       // Keep this location "after" all others when tabbing
+                       info.addReplacementLocation(defaultEndOffs, 
defaultEndOffs);
+               }
+               info.setDefaultEndOffs(defaultEndOffs);
                info.setTextToInsert(sb.toString());
+
                return info;
 
        }
@@ -182,23 +218,102 @@ public class TemplateCompletion extends 
AbstractCompletion
        }
 
 
-       public String toString() {
-               return getDefinitionString();
+       /**
+        * Returns whether a parameter is already defined with a specific name.
+        *
+        * @param name The name.
+        * @return Whether a parameter is defined with that name.
+        */
+       private boolean isParamDefined(String name) {
+               for (int i=0; i<getParamCount(); i++) {
+                       Parameter param = getParam(i);
+                       if (name.equals(param.getName())) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+
+       /**
+        * Parses a template string into logical pieces used by this class.
+        *
+        * @param template The template to parse.
+        */
+       private void parse(String template) {
+
+               int offs = 0;
+               int lastOffs = 0;
+
+               while ((offs=template.indexOf('$', lastOffs))>-1 && 
offs<template.length()-1) {
+
+                       char next = template.charAt(offs+1);
+                       switch (next) {
+                               case '$': // "$$" => escaped single dollar sign
+                                       addTemplatePiece(new TemplatePiece.Text(
+                                                       
template.substring(lastOffs, offs+1)));
+                                       lastOffs = offs += 2;
+                                       break;
+                               case '{': // "${...}" => variable
+                                       int closingCurly = 
template.indexOf('}', offs+2);
+                                       if (closingCurly>-1) {
+                                               addTemplatePiece(new 
TemplatePiece.Text(
+                                                               
template.substring(lastOffs, offs)));
+                                               String varName = 
template.substring(offs+2, closingCurly);
+                                               if (!"cursor".equals(varName) 
&& isParamDefined(varName)) {
+                                                       addTemplatePiece(new 
TemplatePiece.ParamCopy(varName));
+                                               }
+                                               else {
+                                                       addTemplatePiece(new 
TemplatePiece.Param(varName));
+                                               }
+                                               lastOffs = offs = closingCurly 
+ 1;
+                                       }
+                                       break;
+                       }
+
+               }
+
+               if (lastOffs<template.length()) {
+                       String text = template.substring(lastOffs);
+                       addTemplatePiece(new TemplatePiece.Text(text));
+               }
+
        }
 
 
-       public static class TemplatePiece {
+       private int possiblyReplaceTabsWithSpaces(StringBuffer sb, 
JTextComponent tc,
+                                                                               
        int start) {
 
-               private String id;
-               private String text;
-               private boolean isParam;
+               int size = 4;
+               Document doc = tc.getDocument();
+               if (doc != null) {
+                       Integer i = (Integer) 
doc.getProperty(PlainDocument.tabSizeAttribute);
+                       if (i != null) {
+                               size = i.intValue();
+                       }
+               }
+               String tab = "";
+               for (int i=0; i<size; i++) {
+                       tab += " ";
+               }
 
-               public TemplatePiece(String id, String text, boolean isParam) {
-                       this.id = id;
-                       this.text = text;
-                       this.isParam = isParam;
+               int lastNewline = sb.lastIndexOf("\n");
+               int lineOffs = 0;
+               for (int j=lastNewline+1; j<sb.length(); j++) {
+                       if (sb.charAt(j)=='\t') {
+                               int count = size - (lineOffs%size);
+                               sb.replace(j, j+1, tab.substring(0, count));
+                               start += count - 1;
+                       }
                }
 
+               return start;
+
+       }
+
+
+       public String toString() {
+               return getDefinitionString();
        }
 
 
diff --git a/src/org/fife/ui/autocomplete/TemplatePiece.java 
b/src/org/fife/ui/autocomplete/TemplatePiece.java
new file mode 100644
index 0000000..df69343
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/TemplatePiece.java
@@ -0,0 +1,63 @@
+package org.fife.ui.autocomplete;
+
+
+/**
+ * A piece of a <code>TemplateCompletion</code>.  You add instances of this
+ * class to template completions to define them.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ * @see TemplateCompletion
+ */
+interface TemplatePiece {
+
+
+       String getText();
+
+
+       public class Text implements TemplatePiece {
+
+               private String text;
+
+               public Text(String text) {
+                       this.text = text;
+               }
+
+               public String getText() {
+                       return text;
+               }
+
+       }
+
+
+       public class Param implements TemplatePiece {
+
+               String text;
+
+               public Param(String text) {
+                       this.text = text;
+               }
+
+               public String getText() {
+                       return text;
+               }
+
+       }
+
+
+       public class ParamCopy implements TemplatePiece {
+
+               private String text;
+
+               public ParamCopy(String text) {
+                       this.text = text;
+               }
+
+               public String getText() {
+                       return text;
+               }
+
+       }
+
+
+}
\ No newline at end of file

-- 
Alioth's /usr/local/bin/git-commit-notice on 
/srv/git.debian.org/git/pkg-java/autocomplete.git

_______________________________________________
pkg-java-commits mailing list
[email protected]
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-java-commits

Reply via email to